---
title: "Linear Regression: Where Did That Prediction Come From?"
description: "From a 20-minute delivery estimate to LLM latency: explore how a line learns, why we square its mistakes, and when a good-looking prediction stops being useful."
date: "2026-09-05"
updatedAt: "2026-09-05"
author:
  name: "Harsh Sinha"
  url: "https://www.harshsinha.dev"
  sameAs: ["https://x.com/sinhaharsh12","https://www.linkedin.com/in/harshsinha12/","https://www.github.com/harshsinha-12"]
canonical: "https://www.harshsinha.dev/articles/linear-regression-a-line-that-learns"
markdown: "https://www.harshsinha.dev/articles/linear-regression-a-line-that-learns/article.md"
tags: ["Machine Learning","Statistics","LLM"]
---

> AI-readable source for [the published article](https://www.harshsinha.dev/articles/linear-regression-a-line-that-learns). Interactive components are preserved as MDX, and their structured datasets are included at the end.

## Section links

- [1. What can five deliveries tell us?](https://www.harshsinha.dev/articles/linear-regression-a-line-that-learns#1-what-can-five-deliveries-tell-us)
- [2. A starting time, plus a little more per kilometre](https://www.harshsinha.dev/articles/linear-regression-a-line-that-learns#2-a-starting-time-plus-a-little-more-per-kilometre)
- [3. But why this particular line?](https://www.harshsinha.dev/articles/linear-regression-a-line-that-learns#3-but-why-this-particular-line)
- [4. Give every mistake a number](https://www.harshsinha.dev/articles/linear-regression-a-line-that-learns#4-give-every-mistake-a-number)
- [5. Why square the errors?](https://www.harshsinha.dev/articles/linear-regression-a-line-that-learns#5-why-square-the-errors)
- [6. Make a prediction. Then ask how far we wandered](https://www.harshsinha.dev/articles/linear-regression-a-line-that-learns#6-make-a-prediction-then-ask-how-far-we-wandered)
- [7. An error of 0.8 minutes sounds excellent](https://www.harshsinha.dev/articles/linear-regression-a-line-that-learns#7-an-error-of-08-minutes-sounds-excellent)
- [8. One strange trip can move the whole line](https://www.harshsinha.dev/articles/linear-regression-a-line-that-learns#8-one-strange-trip-can-move-the-whole-line)
- [9. Same idea, different wait: LLM latency](https://www.harshsinha.dev/articles/linear-regression-a-line-that-learns#9-same-idea-different-wait-llm-latency)
- [10. But does the relationship survive production?](https://www.harshsinha.dev/articles/linear-regression-a-line-that-learns#10-but-does-the-relationship-survive-production)
- [11. What is worth keeping in your head?](https://www.harshsinha.dev/articles/linear-regression-a-line-that-learns#11-what-is-worth-keeping-in-your-head)

## Author profiles

- [Website](https://www.harshsinha.dev)
- [Twitter](https://x.com/sinhaharsh12)
- [LinkedIn](https://www.linkedin.com/in/harshsinha12/)
- [GitHub](https://www.github.com/harshsinha-12)

The restaurant is four kilometres away and Zomato says your food will arrive in 20 minutes. Where did that 20 come from?

Maybe the system knows about traffic, the restaurant's queue, and the delivery partner's location. But suppose we have just one piece of information: distance.

Could that alone give us a useful estimate?

Let's try it with five deliveries. Once we understand the idea, we'll use the same reasoning for a different wait: an LLM generating an answer.

<Callout title="A small experiment, not a delivery benchmark">
  All observations in this article are fictional teaching data. This is not a description of Zomato's actual model. Hover, tap, or use a chart's arrow-key navigation to inspect values. “View chart data” opens the numbers, and the short exercises have answers you can reveal.
</Callout>

## 1. What can five deliveries tell us?

Here is what we recorded:

```text
1 km → 12 minutes
2 km → 13 minutes
3 km → 17 minutes
4 km → 19 minutes
5 km → 24 minutes
```

<Chart dataset="deliveries" type="bar" title="Distance gives us a useful clue" xKey="distanceKm" series="deliverySeries" yUnit=" min" caption="Horizontal axis: kilometres. Vertical axis: minutes. Each bar is one fictional delivery, not an average of many trips." />

Longer trips took longer. But the increases were uneven: one extra minute between the first two trips, then four, then two, then five.

So distance seems useful, but it does not explain everything. That feels reasonable. A traffic light has very little interest in keeping our dataset tidy.

We want a rule that captures the broad pattern without pretending every delivery behaves identically.

## 2. A starting time, plus a little more per kilometre

One possible rule is:

```text
predicted time
= starting time
+ time added per kilometre × distance
```

Try a starting time of eight minutes and three extra minutes per kilometre:

```text
1 km → 8 + 3 × 1 = 11 minutes
2 km → 8 + 3 × 2 = 14 minutes
3 km → 8 + 3 × 3 = 17 minutes
```

Each extra kilometre adds the same amount. Plot those predictions and you get a straight line.

The starting height is called the **intercept**. The amount added for each extra unit of distance is the **slope**. Finding those two numbers from examples is what we're doing here with **simple linear regression**.

Now the usual notation has somewhere to land:

```text
ŷ = β₀ + β₁x

x  = distance
ŷ  = predicted time
β₀ = intercept, here 8 minutes
β₁ = slope, here 3 minutes per kilometre
```

That little hat over `y` means “predicted.” The actual delivery time can be different.

<details>
  <summary>What does this rule predict for the four-kilometre restaurant?</summary>
  <p><strong>20 minutes.</strong> That's 8 + 3 × 4. The trip in our table took 19 minutes, so this prediction is one minute too high.</p>
</details>

It is tempting to call the eight-minute intercept “preparation time.” It could reflect something like that, but we have not measured preparation separately. We do not even have a zero-kilometre delivery. A plausible interpretation is still an interpretation.

## 3. But why this particular line?

Why eight and three? Why not eight and four?

Or why not skip distance entirely and predict 17 minutes for everyone? That is the average of our five delivery times. It is a perfectly reasonable baseline to beat.

<Chart dataset="candidateLines" type="line" title="Three rules, three sets of predictions" xKey="distanceKm" series="candidateSeries" yUnit=" min" caption="Horizontal axis: kilometres. These lines show predictions. The observed delivery times are in the first chart." />

At five kilometres, the flat rule predicts 17 minutes, the green line predicts 23, and the steeper line predicts 28. Reality, in our little dataset, was 24.

The green line wins that round. But choosing a model based on one convenient example would be a fairly generous marking scheme.

We need to score all five predictions.

## 4. Give every mistake a number

Take what actually happened and subtract what the line predicted:

```text
observed − predicted = residual
```

That difference is called a **residual**. It tells us how far the fitted line misses an observation, including the direction of the miss.

At one kilometre, we observed 12 minutes and predicted 11. The residual is `+1`: the delivery was slower than expected. At two kilometres, it is `13 − 14 = −1`: faster than expected.

<Chart dataset="residuals" type="bar" title="The line's mistakes, one trip at a time" xKey="distanceKm" series="residualSeries" yUnit=" min" caption="Above zero: slower than predicted. Below zero: faster than predicted. At three kilometres, the line gets this observation exactly right." />

Now add those mistakes:

```text
+1 − 1 + 0 − 1 + 1 = 0
```

Zero total error. Four wrong predictions. Clearly, adding signed mistakes is letting them cancel each other out.

We need a score that keeps track of their size.

## 5. Why square the errors?

One option is to square each mistake before adding:

```text
1² + (−1)² + 0² + (−1)² + 1² = 4
```

Both `+1` and `−1` now contribute one. A four-minute miss contributes 16. So squaring does two jobs: it prevents cancellation and makes big mistakes disproportionately expensive.

The rule is then: choose the intercept and slope with the smallest total squared error. That method is called **ordinary least squares**. [NIST's least-squares guide](https://www.itl.nist.gov/div898/handbook/pmd/section4/pmd431.htm) gives the objective and the straight-line solution.

<Chart dataset="modelErrors" type="bar" title="Does distance beat guessing the average?" xKey="model" series="errorSeries" caption="Sum of squared errors on the same five trips, in squared minutes. Lower is better: fitted line 4, steep line 59, flat baseline 94." />

Our `8 + 3 × distance` line scores four. It is the best of these three, and the least-squares solution among all possible straight lines for these observations.

But squaring is a choice. We could instead add absolute errors: turn `−1` into `1` without squaring. That also prevents cancellation and is less dominated by a single huge miss. Optimizing that score is a different fitting method and can produce a different line.

Squared error has a convenient mathematical shape: for this problem, the score forms a convex bowl as we vary the slope and intercept. With distances that are not all identical, there is one bottom. We can solve for it directly; we do not need to guess lines forever.

<details>
  <summary>Show me how the calculation finds 8 and 3</summary>
  <p>The average distance is 3 km. The average time is 17 minutes. Subtract those averages from each observation:</p>
  <p><code>distance differences: −2, −1, 0, 1, 2</code></p>
  <p><code>time differences: −5, −4, 0, 2, 7</code></p>
  <p>Multiply matching differences and add: 10 + 4 + 0 + 2 + 14 = 30. Square the distance differences and add: 4 + 1 + 0 + 1 + 4 = 10.</p>
  <p><code>slope = 30 / 10 = 3</code></p>
  <p><code>intercept = average time − slope × average distance = 17 − 3 × 3 = 8</code></p>
  <p>If every recorded distance were identical, the denominator would be zero. Those observations could tell us about time at that distance, but not how time changes with distance.</p>
</details>

That is what the model learned: two numbers chosen to minimize a particular definition of “wrong.”

## 6. Make a prediction. Then ask how far we wandered

A restaurant 3.5 kilometres away gives us:

```text
8 + 3 × 3.5 = 18.5 minutes
```

We did not record that exact distance, but it sits between distances we did record. This is **interpolation**.

<details>
  <summary>What happens if the restaurant is 30 kilometres away?</summary>
  <p>The line predicts <strong>98 minutes</strong>: 8 + 3 × 30. It will happily do that calculation even though our data only covers 1–5 kilometres.</p>
</details>

Now we are **extrapolating**: going outside the range we observed. A 30-kilometre trip could involve highways, different delivery arrangements, or a completely different relationship between distance and time.

The maths still works. Whether the prediction does is another question. Extrapolation is one of the limitations highlighted in [NIST's overview of linear regression](https://www.itl.nist.gov/div898/handbook/pmd/section1/pmd141.htm).

Even the 3.5-kilometre estimate is not guaranteed. Staying inside the range removes one reason for concern; it does not remove traffic.

## 7. An error of 0.8 minutes sounds excellent

Let's report a score in minutes instead of squared minutes. Take the size of each miss and average it:

```text
mean absolute error = (1 + 1 + 0 + 1 + 1) / 5
                    = 0.8 minutes
```

That is **MAE**, or mean absolute error. We fitted using squared error, but we can still evaluate the result using a metric that is easier to interpret.

Less than a minute off, on average. Pretty good.

But we measured it on the same five examples used to choose the line. And I made those examples deliberately tidy. Neither detail belongs in the footnotes of a performance claim.

To find out whether the model is useful, fit it on one set of trips and evaluate it on trips it has not seen. For tomorrow's deliveries, a test set from a later period is a useful way to mimic the actual task. Do not use those test outcomes to keep adjusting the line and still call them an untouched test.

This distinction between training and test error is fundamental to evaluating predictions; see [An Introduction to Statistical Learning, Chapter 2](https://www.statlearning.com/s/ISLRSeventhPrinting.pdf).

<Callout title="What the score does not say">
  Our training MAE is 0.8 minutes. We have not measured test performance. It also does not mean that every future delivery will arrive within ±0.8 minutes of its prediction.
</Callout>

## 8. One strange trip can move the whole line

Suppose the five-kilometre delivery took 44 minutes instead of 24. Perhaps the rider got stuck. Perhaps someone typed the number incorrectly.

Against our original line, that trip's miss jumps from one minute to 21 minutes. Its contribution to squared error jumps from `1` to `441`.

Refit using that changed observation and the equation becomes:

```text
predicted time = 0 + 7 × distance
```

One changed row moves the slope from three to seven. The new line predicts seven minutes at one kilometre, even though that observation is still 12.

<Chart dataset="outlierPredictions" type="line" title="One changed observation pulls the fitted line" xKey="distanceKm" series="outlierSeries" yUnit=" min" caption="Predictions before and after replacing the five-kilometre observation of 24 minutes with 44. All other observations stay unchanged. Horizontal axis: kilometres." />

That is the other side of making large errors expensive. Least squares tries hard to accommodate them. [NIST notes this sensitivity to unusual observations](https://www.itl.nist.gov/div898/handbook/pmd/section1/pmd141.htm).

The response should start with investigation. Correct a verified data-entry error. Keep a genuine difficult trip in the picture when deciding what the system must handle. Deleting an inconvenient observation because it spoils the chart is not model improvement.

Also inspect the shape of the residuals. A curve can suggest the straight-line relationship is missing something. An expanding spread can suggest predictions become less precise as distance grows. Five trips are enough for this arithmetic, but too few for confident diagnostics.

## 9. Same idea, different wait: LLM latency

Now replace kilometres with generated tokens, and delivery minutes with response milliseconds.

Suppose we record output length and elapsed time until the full response completes. Keep the model and serving setup fixed, and use requests with similar input lengths. Here is another fictional dataset:

```text
100 output tokens →  850 ms
200 output tokens → 1150 ms
300 output tokens → 1600 ms
400 output tokens → 1950 ms
500 output tokens → 2450 ms
```

The same calculation gives:

```text
predicted completion time = 400 + 4 × output tokens
```

<Chart dataset="llmLatency" type="bar" title="Can output length help estimate completion time?" xKey="outputTokens" series="llmSeries" yUnit=" ms" caption="Fictional observations and their least-squares predictions. Horizontal axis: output tokens. Vertical axis: time until the full response completes, not time to first token. This is not a provider benchmark." />

At 300 tokens, the prediction is `400 + 4 × 300 = 1,600 ms`. The fitted slope says that one additional output token is associated with four additional milliseconds in these examples.

It does not prove that the hardware spends exactly four milliseconds on every token. The intercept is not a measured breakdown of network and processing overhead either. We fitted a relationship, not a profiler trace.

<details>
  <summary>A 350-token answer would take how long under this model?</summary>
  <p><strong>1,800 ms</strong>, or 1.8 seconds: 400 + 4 × 350. That is within the observed output-length range, but still depends on the serving conditions remaining comparable.</p>
</details>

There is also a practical catch: before generating an answer, we usually do not know its final token count. This model can help analyze completed requests or estimate time for an assumed output budget. An exact prediction made using the eventual output length is using information we would not have at request arrival.

That distinction matters if someone presents it as a live ETA system.

## 10. But does the relationship survive production?

Suppose the fit came from quiet periods. Now requests queue behind other work. Two answers with the same output length can have very different total completion times.

Or we change the model, hardware, input lengths, or serving configuration. The line might need to change too. Our five synthetic observations establish nothing about those cases.

We could record additional inputs and fit **multiple linear regression**:

```text
predicted completion time
= intercept
+ output-length coefficient × output tokens
+ input-length coefficient × input tokens
+ queue coefficient × queue depth at arrival
```

This is a candidate model to test, not a claim that queue behaviour is linear. Adding columns cannot make an unsuitable relationship suitable. We also need enough varied observations to estimate their effects, and each input must be available when we intend to make the prediction.

For a real evaluation, I would compare the model with a simple baseline on later requests, inspect errors across output lengths and load levels, and check the slow requests separately. An average error can look comfortable while the people waiting longest get terrible estimates.

And prediction still is not causation. If longer answers tend to come from harder requests, output length may be mixed up with other sources of delay. A fitted coefficient alone does not establish what would happen if we intervened and changed only one variable. [Chapter 3 of An Introduction to Statistical Learning](https://www.statlearning.com/s/ISLRSeventhPrinting.pdf) develops these questions of regression interpretation and model checking.

## 11. What is worth keeping in your head?

A line is a compact rule: start here, then add this much for each extra unit of input. Least squares chooses that rule by minimizing squared mistakes on the examples we give it.

Everything useful comes after asking what those examples represent. Which range did we observe? What information was available at prediction time? What changed between fitting and using the model?

The next time an app promises food in 20 minutes, or an AI product promises an answer in two seconds, the number is only the beginning.

What taught the system to expect that wait—and does the same relationship still hold when tomorrow's traffic, tokens, or queues look different?

<References dataset="citations" />

## Companion structured data

```json
{
  "dataNote": "All delivery and LLM observations are fictional teaching data, not product or provider benchmarks. The outlier scenario replaces only the five-kilometre delivery time with 44 minutes. Predictions and scores are calculated from the corresponding observations.",
  "outlierSeries": [
    {
      "key": "originalFit",
      "label": "Original fit: 8 + 3 × distance",
      "color": "#356b51"
    },
    {
      "key": "changedFit",
      "label": "Changed observation: 7 × distance",
      "color": "#b65332"
    }
  ],
  "outlierPredictions": [
    {
      "distanceKm": 1,
      "originalFit": 11,
      "changedFit": 7
    },
    {
      "distanceKm": 2,
      "originalFit": 14,
      "changedFit": 14
    },
    {
      "distanceKm": 3,
      "originalFit": 17,
      "changedFit": 21
    },
    {
      "distanceKm": 4,
      "originalFit": 20,
      "changedFit": 28
    },
    {
      "distanceKm": 5,
      "originalFit": 23,
      "changedFit": 35
    }
  ],
  "llmSeries": [
    {
      "key": "observedMs",
      "label": "Observed completion time",
      "color": "#b65332"
    },
    {
      "key": "predictedMs",
      "label": "Fitted completion time",
      "color": "#356b51"
    }
  ],
  "llmLatency": [
    {
      "outputTokens": 100,
      "observedMs": 850,
      "predictedMs": 800
    },
    {
      "outputTokens": 200,
      "observedMs": 1150,
      "predictedMs": 1200
    },
    {
      "outputTokens": 300,
      "observedMs": 1600,
      "predictedMs": 1600
    },
    {
      "outputTokens": 400,
      "observedMs": 1950,
      "predictedMs": 2000
    },
    {
      "outputTokens": 500,
      "observedMs": 2450,
      "predictedMs": 2400
    }
  ],
  "deliverySeries": [
    {
      "key": "actual",
      "label": "Observed delivery time"
    }
  ],
  "candidateSeries": [
    {
      "key": "flat",
      "label": "Always 17 minutes",
      "color": "#88619a"
    },
    {
      "key": "fitted",
      "label": "8 + 3 × distance",
      "color": "#356b51"
    },
    {
      "key": "steep",
      "label": "8 + 4 × distance",
      "color": "#b65332"
    }
  ],
  "residualSeries": [
    {
      "key": "residual",
      "label": "Observed minus predicted",
      "color": "#b65332"
    }
  ],
  "errorSeries": [
    {
      "key": "squaredError",
      "label": "Sum of squared errors"
    }
  ],
  "deliveries": [
    {
      "distanceKm": 1,
      "actual": 12
    },
    {
      "distanceKm": 2,
      "actual": 13
    },
    {
      "distanceKm": 3,
      "actual": 17
    },
    {
      "distanceKm": 4,
      "actual": 19
    },
    {
      "distanceKm": 5,
      "actual": 24
    }
  ],
  "candidateLines": [
    {
      "distanceKm": 1,
      "flat": 17,
      "fitted": 11,
      "steep": 12
    },
    {
      "distanceKm": 2,
      "flat": 17,
      "fitted": 14,
      "steep": 16
    },
    {
      "distanceKm": 3,
      "flat": 17,
      "fitted": 17,
      "steep": 20
    },
    {
      "distanceKm": 4,
      "flat": 17,
      "fitted": 20,
      "steep": 24
    },
    {
      "distanceKm": 5,
      "flat": 17,
      "fitted": 23,
      "steep": 28
    }
  ],
  "residuals": [
    {
      "distanceKm": 1,
      "residual": 1
    },
    {
      "distanceKm": 2,
      "residual": -1
    },
    {
      "distanceKm": 3,
      "residual": 0
    },
    {
      "distanceKm": 4,
      "residual": -1
    },
    {
      "distanceKm": 5,
      "residual": 1
    }
  ],
  "modelErrors": [
    {
      "model": "Fitted",
      "squaredError": 4
    },
    {
      "model": "Steep",
      "squaredError": 59
    },
    {
      "model": "Flat",
      "squaredError": 94
    }
  ],
  "citations": [
    {
      "title": "Least Squares",
      "publisher": "NIST/SEMATECH e-Handbook of Statistical Methods",
      "url": "https://www.itl.nist.gov/div898/handbook/pmd/section4/pmd431.htm",
      "note": "Least-squares objective and the formulas for a straight-line slope and intercept."
    },
    {
      "title": "Linear Least Squares Regression",
      "publisher": "NIST/SEMATECH e-Handbook of Statistical Methods",
      "url": "https://www.itl.nist.gov/div898/handbook/pmd/section1/pmd141.htm",
      "note": "Model definition, extrapolation limitations, and sensitivity to unusual observations."
    },
    {
      "title": "An Introduction to Statistical Learning, second edition",
      "publisher": "Gareth James, Daniela Witten, Trevor Hastie, and Robert Tibshirani",
      "url": "https://www.statlearning.com/s/ISLRSeventhPrinting.pdf",
      "note": "Chapter 2 covers training and test error; Chapter 3 develops linear regression and its interpretation."
    }
  ]
}
```
