The problem in brief
In an imaginary kingdom, people keep records of their snowmen. For 1 000 weeks you get nine weekly statistics (temperature, wind speed and direction, precipitation, number of frosty days, price of carrots, a scarf-sale flag, number of action movies released, firewood consumption) and the number of snowmen counted. You must predict the count for 1 000 other weeks. The starter notebook "trains" a DummyRegressor, which always predicts the mean, and the only stated goal is to do better than it.
The data and starter notebook are in the official HAIO repository; the test labels are not public, and the Kaggle page is gone. We therefore evaluate on the starter notebook's own split of the labelled data (20 % held out, random_state=43), and all the detective work below uses only the other 80 %.
How you are scored
The metric is the root mean squared error:
It is in the unit of the target (snowmen), and squaring makes large errors dominate. The target to beat is the DummyRegressor: on the held-out split it scores 66 229, basically the standard deviation of the counts.
First look at the data
Three facts jump out in the first five minutes.
- Almost half the weeks (48 %) have exactly 0 snowmen, and the others range up to 212 000. The counts are all integers.
- Linear correlations are tiny. The strongest is temperature, at only ; every other column is below in absolute value. A careless contestant would conclude "nothing predicts anything".
- Plotting tells the opposite story (left panel below). Snowmen exist only between about °C and °C, and their number traces a clean upside-down parabola peaking near °C: too warm, the snow melts; too cold, the snow is powder and nobody goes out. A correlation coefficient measures linear association, so it is blind to a hump: the rising and falling halves cancel out.

The colours add a second clue: at a given temperature, wetter weeks (yellow-green) have more snowmen. More snow, more snowmen.
A first baseline
| model on the 9 raw columns | held-out RMSE |
|---|---|
DummyRegressor (predict the mean) | 66 229 |
| linear regression | 66 137 |
| random forest (500 trees) | 6 196 |
| gradient boosting (800 rounds) | 3 739 |
Linear regression is no better than the mean: it can only draw a straight line through a hump. Tree ensembles, which cut the temperature axis into pieces, already divide the error by 18. Most contestants would stop here, happy to beat the baseline by a factor of 18. But the data look synthetic: a fictional kingdom, integer counts, a perfectly smooth parabola. That suggests a hidden formula, and if we can find it we can do far better than any tree.
The key idea
Fit the formula, not a black box: model the weeks with snowmen with a linear model, read the residuals, add the feature that explains them, and repeat.
Two technical points make this work.
- Fit only the weeks with snowmen. The zeros are a floor: the count cannot go negative, so the true process looks like . Inside the zero region, is some negative number that we never see. Fitting a linear model to the zeros would bend it. So we fit on the 417 positive training weeks, and predict everywhere.
- Let the residuals point to the next feature. After each fit, compute the residuals and find which candidate feature correlates most with them.
Here is the whole investigation, every step decided on the training part only:
| step | features of | train residual std | strongest correlate of the residual | held-out RMSE |
|---|---|---|---|---|
| 1 | , | 14 885 | precipitation, | 10 181 |
| 2 | + precipitation | 7 323 | , | 5 808 |
| 3 | + north wind | 481 | frost days , | 356 |
| 4 | + | 27.2 | action movies, | 19.0 |
| 5 | + action movies | 0.29 | scarf flag, (nothing left) | 0.22 |
Each step needed a small idea:
- Step 2 → 3: the wind. Wind speed and direction show no correlation with the residual separately. But a direction measured "relative to north" in radians invites a vector reading: the north-south component of the wind is . Its correlation with the residual is 0.992 (right panel above): a perfectly straight line. Speed and direction were only useful together, which no correlation table of single columns could reveal.
- Step 3 → 4: a threshold. The residual grouped by number of frosty days is about for 1 to 3 days and about for 4 to 7 days, flat within each group. That is a step, not a slope, so the right feature is the indicator .
- Step 4 → 5: the residual is then almost perfectly (anti)correlated with the number of action movies: each one costs about 16 snowmen (people stay at the cinema?).
After step 5 the residual standard deviation is 0.29. That is exactly the standard deviation of a rounding error: a value spread uniformly over has standard deviation . In other words, nothing is left but the rounding to whole snowmen. Carrot prices, scarf sales and firewood play no role at all (they are decoys).
The recovered formula, with coefficients that land on round numbers:
Completing the square, : the hump is centred at exactly °C, as the plot suggested.
The full solution
- Add three engineered features: , the north wind and the indicator .
- Fit an ordinary linear regression on the training weeks with at least one snowman, using .
- Predict and round to the nearest integer.
f["T2"] = d.temperature ** 2
f["north_wind"] = d.wind_speed * np.cos(d.wind_direction)
f["freeze_4plus"] = (d.freeze_days >= 4).astype(int)
lin = LinearRegression().fit(F.iloc[pos][cols], y[pos]) # pos = weeks with snowmen
pred = np.round(np.clip(lin.predict(F_test[cols]), 0, None))
Fitted coefficients: , , , , , , intercept .
Results
| approach | held-out RMSE |
|---|---|
starter DummyRegressor | 66 229 |
| linear regression, raw columns | 66 137 |
| random forest, raw columns | 6 196 |
| gradient boosting, raw columns | 3 739 |
| clip(linear: ) | 10 181 |
| clip(linear: + ) | 5 808 |
| clip(linear: + north wind) | 356 |
| clip(linear: + frost days ) | 19.0 |
| clip(linear: + action movies) | 0.22 |
| final: same, rounded to integers | 0.16 |

The final model reaches a held-out RMSE of 0.16 snowmen, against 66 229 for the baseline to beat: it reproduces the generating formula, and its remaining errors are a few rounding ties. Gradient boosting, the best black box, stays 20 000 times worse, because trees approximate a smooth surface with steps and need far more than 800 examples to draw a parabola, a vector component and a threshold precisely.
What to remember
- Plot before you trust a correlation. Temperature has a correlation of and explains most of the target: correlation only measures straight-line relations.
- Residuals are a to-do list. Fit, look at what is left, find what correlates with it, add it, repeat. When the residual becomes pure noise (here the of rounding), stop.
- Think about what a column means. A direction and a speed together form a vector; a count of frosty days may act through a threshold. Physical reasoning creates the features that no single column shows.
- Handle floors explicitly. When a target is clipped at 0, fit the underlying quantity on the unclipped part and clip the prediction.
- Suspect synthetic data. Round coefficients, integer targets, decoy columns: on generated data, recovering the formula beats any model.