The result looked great: R2 of 0.9993 and a correlation of 0.9994 between speed and distance. The problem was that the data had no real relationship in it.

What the script does

  1. Generates 1,000 random speed values (10 to 1,000) and 1,000 random distance values (100 to 10,000) independently with random.randint.
  2. Sorts both arrays ascending, separately.
  3. Pairs them by index into a DataFrame and saves speed_dist.csv.
  4. Splits 97/3 into train and test (970 and 30 rows).
  5. Fits a LinearRegression of distance on speed and reports R2 on the test set.

How I caught it

Speed and distance were generated independently, so by construction there should be no relationship between them. A near-perfect fit should not have been possible. That mismatch made me look at step 2.

Sorting two unrelated arrays and lining them up by index forces a monotonic pattern. Row 1 gets the smallest speed and the smallest distance, row 1,000 gets the largest of both, and nothing about speed and distance is actually connected.

Testing the suspicion

I generated the same two arrays with the same seed and skipped the sorting step:

Correlation Test R2
With sorting (original script) 0.9994 0.9993
Without sorting (random pairing) 0.0055 -0.0168

Without the sort, the correlation falls to about zero, and R2 goes negative. A negative R2 means the model does worse than predicting the average distance every time. The high score came entirely from how I assembled the data.

What I do differently now

A high R2 or accuracy only means something if you know exactly how the data was built. Since this project, I check how any synthetic or generated data was assembled before I trust a metric computed from it.

Code: github.com/bluntjudg/Speed-distance-model-

Series: Part 6 of 7 in my ML fundamentals revisit. Next in the series: Gender Classification.

Live projects I built after these basics:

More of my work is on GitHub.