Ryan Allen
All projects

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.

Random forest out-of-bag error by maximum tree depth: 63.5 at depth 3, 54.0 at 5, 45.0 at 8, 37.8 at 12, then about 37.2 from depth 16 on.02040608035812162030Maximum tree depthOut-of-bag MSE63.537.2
Random forest error on the races each tree didn't see while training (out-of-bag MSE), by maximum tree depth.

Then I compared the tuned random forest with ordinary least squares (OLS) regression and gradient boosting on the same held-out races.

Test error by model: random forest 35.41, OLS regression 29.96, gradient boosting 29.07. Lower is better.010203040Random forest35.41OLS regression29.96Gradient boosting29.07
Test error (mean squared error, in championship points squared) on held-out races. Lower is better.

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.

StatLevelPoints per level (OLS)
Horsepower100+0.24
Braking efficiency100+0.18
Track skill90+0.16
Grip80
Reaction time80
Low-friction skill80
Downforce coefficient70
Aggressiveness70
Reliability50
Car weight40−0.19
Torque, aero balance, gearing, driver experience, consistency40

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.