Race-car performance model
Predicting championship points from 60,000 simulated races, then spending a fixed 1,000-point upgrade budget where the model said it would pay off most.
- Course
- INEG 22203 Computing Methods for Industrial Engineers II, Assignment 4
- Term
- Fall 2026
- Work
- Individual
- Tools
- Java, Tablesaw, Smile
- Result
- 70.49 points per race in the season simulation; the dataset average is 47.5
The task
The data held 60,000 races. Each row has a racer's 15 car and driver ratings (horsepower, torque, weight, grip, braking, reaction time and so on), the weather, the track type, the temperature, and the championship points that racer scored. The job had two parts: build models that predict points, then design my own racer with 1,000 upgrade points, where each level costs more than the one before, and enter it in the instructor's season-long simulation.
Preparing the data
Regression and tree models only do math on numbers, so I turned the weather, track type and temperature into impact scores: penalties for conditions that slow a racer down, with sun on asphalt as the baseline. Temperature became a penalty for being too hot or too cold rather than a raw number, because its effect isn't a straight line. A model given raw temperature would assume hotter is always better or always worse.
Choosing features
Correlation matrices showed two redundant pairs: horsepower with torque, and downforce with aero balance. Each pair carries the same information, so a model splits the credit between them and neither looks important. Feature importance from a random forest flagged the weakest predictors. I dropped four features, the redundant half of each pair and two that each contributed under 1%, and test error went down slightly (MSE from 35.96 to 35.72).
Tuning and comparing models
Tuning the random forest one setting at a time showed that tree depth mattered far more than anything else. Shallow trees can't make enough splits to capture the pattern, so they underfit; past a depth of about 16 the error levels off. More trees and bigger leaves barely moved it.
Then I compared the tuned random forest with ordinary least squares (OLS) regression and gradient boosting on the same held-out races.
Gradient boosting was the most accurate, but only just: OLS was within 0.9 of it and beat the random forest, which overfit. That suggests a racer's points are mostly the sum of each stat's effect plus the condition penalties, which is exactly what a linear model assumes.
Spending the budget
I used OLS for the build, even though it was slightly less accurate, because it gives a plain number for every stat: how many points one more level is worth. That turned the budget into a marginal-value problem. Upgrades get more expensive at higher levels, so I compared each stat's points per level with the cost of its next level and spent where the return was highest.
| Stat | Level | Points per level (OLS) |
|---|---|---|
| Horsepower | 100 | +0.24 |
| Braking efficiency | 100 | +0.18 |
| Track skill | 90 | +0.16 |
| Grip | 80 | |
| Reaction time | 80 | |
| Low-friction skill | 80 | |
| Downforce coefficient | 70 | |
| Aggressiveness | 70 | |
| Reliability | 50 | |
| Car weight | 40 | −0.19 |
| Torque, aero balance, gearing, driver experience, consistency | 40 |
Every stat starts at 40, the minimum. The total cost was exactly 1,000 points.
Car weight had a negative coefficient (a heavier car scores fewer points), so it stayed at the minimum. So did the stats that were redundant or barely mattered.
Result
The model predicted my racer would average about 71.1 points across four test conditions, from 79.7 in sun on asphalt down to 61.1 in snow on dirt. In the instructor's season simulation it averaged 70.49 points per race, close to the prediction and well above the 47.5-point average of the racers in the data.
The gap of about 18 points between the sunny and snowy races is the part no build can buy back: conditions still matter whatever you spend.
Help I had: Claude explained the three model types and helped me with feature importance and debugging, and classmates Sam Brown and Damir Ashinov helped with Tablesaw loops, the Spearman correlation and setting up the random forest.