Toby Lowe Analysis you can check · Manchester

Work MSc coursework · 2026-01

Forecasting six weeks of Rossmann store sales

Can six weeks of daily sales be forecast across the 1,115 Rossmann Germany stores in the dataset from store metadata, promotion schedules and calendar effects, and which model class handles that tabular structure best?

In one lineXGBoost at RMSPE 0.1867 against a 0.4383 linear baseline — one holdout split, no intervals, no significance test.

Attribution
Attribution unclear in the source. The cover page carries only my student ID but also names the module cohort team, and the body is written in the first person plural. I have not resolved which it was rather than claim the more flattering reading.
Methods
MICE imputation · missingness-mechanism diagnosis · feature engineering · exploratory data analysis · linear regression · neural network (MLP) · XGBoost · time-based holdout validation
Tools
Python · pandas · seaborn · calplot · XGBoost · LaTeX

The question

The dataset covers 1,115 Rossmann Germany drug stores — a slice of a group the report puts at over 3,200 European stores in 2015 — and the brief for DATA71011 was to predict six weeks of daily sales across all of them. The commercial framing is inventory: overstocking can lead to markdowns and write-offs against gross margin, understocking to lost sales (Sant 2024).

The target was set by the brief, not discovered, and the sales files were supplied rather than collected. The open part was methodological: how to treat three distinct missingness mechanisms, and which model class copes with a tabular series mixing continuous distances, categorical store types and hard calendar rules.

On attribution: the report carries one student ID (11139102) beside a "Gold Group" label and calls itself "A student forecasting report", yet uses the first person plural throughout, switching to "my analysis" only in the limitations. With no author list, I do not claim sole authorship.

The data

Three files: train.csv with 1,017,209 daily sales rows, plotted over 2013–2015; store.csv with 1,115 metadata records; test.csv with 41,088 rows the report never scores against. The schema was disconnected — sales sat isolated from causal variables like store type and competition data — so a left join came first.

Missingness sat in the metadata: 544 stores had nulls in Promo2SinceWeek and Promo2SinceYear, 3 lacked CompetitionDistance, 354 lacked competition opening dates, and CompetitionDistance was right-skewed.

The structural problems mattered more. DayOfWeek=7 implies zero sales for 98% of the dataset, but high sales for store type 'b', which trades seven days a week with near-100% opening on Sundays and state holidays while types 'a', 'c' and 'd' close under German trading law. Type 'b' is also far less common than the others, so the segment with fewest observations is the one breaking the dominant pattern. No result is reported against test.csv, so every number below comes from held-out training data.

Approach

Imputation was tiered by mechanism. The 544 Promo2 nulls were not missing at all — 100% occurred where the store did not participate — so they were set to 0. The 3 missing distances took the median, since the right skew would let outliers drag a mean.

For the 354 missing competition dates, mean CompetitionDistance was near-identical with and without the date (5,393m against 5,431m), read as support for a Missing At Random hypothesis. That licensed MICE conditioned on StoreType, Assortment and CompetitionDistance, since a flat median ignores that stores sit in different competitive environments.

CompetitionOpenSinceYear is a static year saying nothing about how long a competitor has been present, so it became a duration, max(0, (D_sales − D_open) / 30.4375); the max(0) stops future competitors exerting negative pressure. PromoInterval was a string ("Jan,Apr,Jul,Oct") a neural network cannot consume, so it became a binary IsPromo2Active flag.

Three models were then compared on RMSPE, assessing them against percentage deviations rather than raw euro values, with the final six weeks of training data isolated against leakage. Linear regression was a deliberate baseline expected to miss non-linearities like the type 'b' split; the neural network was expected to win, on the strength of the non-linear retail literature; XGBoost followed Krishna et al. (2018).

What I found

XGBoost led on all three reported metrics: RMSPE 0.1867, MAE €773.42, R² 0.8936. The neural network — 64-40-20 with ReLU, 20–40% dropout against overfitting, log-transformed target — reached RMSPE 0.3487, MAE €1499.43, R² 0.6276. Linear regression gave RMSPE 0.4383, MAE €1648.51, R² 0.5454.

These are point estimates from one time-based holdout. The report runs no cross-validation, reports no confidence intervals and performs no significance test, so I cannot say how much of the gap between models would survive a different six-week window.

Descriptively, active promotions were associated with an average uplift of 81.4% in daily sales and school holidays with a 15.2% increase — raw group comparisons, neither tested. Competition proximity "appeared weak": counterintuitively, competitors within 500m showed the highest median sales, with a slight rebound beyond 10km.

What this doesn't show

The report concludes that "the non-random nature of Rossmann's sales has been proven". It does not. An R² of 0.8936 on one holdout window shows the series is predictable from the recorded features on that window; that is not proof, and I would not repeat the claim.

The evaluation is the weakest link: one six-week holdout, one split, no repeated runs, and no statement of which calendar dates it covers — a window containing or excluding the December peak is not equally informative. Nor does the report say whether the network's dropout and log-transform tuning was selected against a separate validation split; if it was tuned against the holdout, 0.3487 is optimistic and the ranking less clean than the table implies.

The MAR check is thinner than it reads: two means, 5,393m against 5,431m, with no test statistic, no interval, and no check against other covariates. MAR is assumed, and MICE inherits that assumption for 354 of 1,115 stores; a sensitivity comparison against median imputation would have shown whether it mattered.

Nothing here is causal. Promotions are not randomly assigned, so the 81.4% uplift bundles the promotion effect with whatever made a store run one. The "special zone" reading of type 'b' — airports or stations — is a hypothesis with no location data behind it. No score is reported against the 41,088 test.csv rows, so there is no external benchmark.

The report names two further gaps: no weather data, and no local footfall or location data. I would add rolling-origin cross-validation, tuning held inside each fold, before claiming XGBoost is the better model rather than the better model on one window.