Integrals: totals and areas
Totals from rates, areas from thin strips, probability as area, and AUC by trapezoids.
Create a free account Try part of it here
Why it matters
Many numbers you care about are totals built from rates: distance from speed, requests from requests per second, tokens from tokens per second, probability from a density. The tool for "add up a rate over a range" is the integral, and geometrically it's the area under a curve. The AUC you've seen for classifiers is literally an area under a curve. This lesson builds integrals from rectangles you can count, then lets Python add up thousands of thin strips, so you'll read "area under the curve" as something you can compute.
What you'll be able to do
- Turn a rate over time into a total by finding the area under its curve
- Estimate an area with thin strips, and with the trapezoid rule, in Python
- Read a probability as the area under a density curve
- Explain how integrals and derivatives undo each other, and compute an AUC from ROC points
What it covers
- Totals from rates
- Smooth curves: thinner and thinner strips
- The trapezoid rule
- Probability is area
- Integrals undo derivatives
- AUC from ROC points
- Integrals in AI
Show the answer
150 km
Distance is speed times time for each stretch: 60 × 2 + 30 × 1 = 150 km. On a chart of speed against time, that's the area of two rectangles, which is exactly what an integral measures.
Totals from rates
A rate says how fast something accumulates: km per hour, requests per second, dollars per day. When a rate is constant, the total is rate × time, which on a chart of rate against time is the area of a rectangle: height (the rate) times width (the time).
When the rate changes in steps, the total is a sum of rectangles, one per step:
speeds = [60, 60, 30] # km/h in each of three hours total = 0 for speed in speeds: total += speed * 1 # each strip is 1 hour wide print(total, "km")
The units check themselves: km per hour times hours gives km, requests per second times seconds gives requests. And a rate can be negative, like refunds flowing out, in which case its area subtracts from the total.
That's the whole idea of an integral: the total of a rate is the area under its curve. The rest of the lesson is about curves that change smoothly, where the rectangles have to get thinner. Real monitoring data often arrives in exactly this stepped form, a reading per minute or per hour, so the rectangle sum is often all you need.
per_second = [10, 12, 15, 11] print(sum(rate * 60 for rate in per_second))
Show the answer
2880
Each minute is 60 seconds, so each strip adds rate × 60: (10 + 12 + 15 + 11) × 60 = 48 × 60 = 2,880 requests.
Smooth curves: thinner and thinner strips
For a smoothly changing rate, cut the range into many thin strips, treat the rate as constant across each strip, and add up the rectangles. Thinner strips give a better estimate, and in the limit you get the exact area, written ∫ (an S for "sum") with the range below and above it. In ∫₀¹ x² dx, the x² is the height of each strip and the dx stands for its width, shrinking toward zero: the notation is a recipe for exactly this sum.
Take the area under y = x² from 0 to 1. Its exact value is 1/3:
def area(f, a, b, n): width = (b - a) / n return sum(f(a + i * width) * width for i in range(n)) # left edge of each strip for n in [4, 40, 400]: print(n, round(area(lambda x: x ** 2, 0, 1, n), 5))
With 4 strips the estimate is 0.219, with 400 it's 0.332: closing in on 1/3. Each strip's height comes from its left edge, so for a rising curve every strip falls a little short, and more strips shrink that shortfall.
Simple curves have exact formulas: the area under xⁿ from 0 to 1 is 1 / (n + 1), which is where the 1/3 comes from. But strips work for any curve at all, including one you only have as a list of measured points, which is the usual situation with real data.
The left-edge estimate of the area under x² from 0 to 1, as the number of strips grows. The exact area is 1/3.
Show the answer
Each strip's flat top fits the curve more closely
Over a narrow strip the curve barely changes, so treating it as flat costs very little. Add up many small errors that keep shrinking, and the total error shrinks too.
The trapezoid rule
Rectangles leave a gap under a rising curve. Trapezoids join each strip's left and right heights with a straight line, which fits much better. Write trapezoid(f, a, b, n): the sum over strips of width × (f(left) + f(right)) / 2. Then set est to the area under x² from 0 to 2 with 100 strips (the exact answer is 8/3).
def trapezoid(f, a, b, n): width = (b - a) / n total = 0 # add width * (f(left) + f(right)) / 2 for each strip return total est = trapezoid(lambda x: x ** 2, 0, 2, 100) print(est)
Probability is area
A continuous quantity, like a delivery time or a model's score, has a density curve. The chance of a value falling between a and b is the area under the curve between them, and the whole area under a density is 1, since the value has to land somewhere.
This is the continuous version of adding up the probabilities of separate outcomes, as you did for dice, with areas taking the place of sums. For the normal distribution, the area within one standard deviation of the mean is about 0.68, the "about two thirds" from the normal distribution lesson. You can check it by adding thin strips under its curve:
import math def normal(x): return math.exp(-x * x / 2) / math.sqrt(2 * math.pi) width = 0.001 print(round(sum(normal(-1 + i * width) * width for i in range(2000)), 3))
A density's height isn't itself a probability, and it can even be above 1 for a narrow curve; only areas under it are probabilities. A single exact value, like exactly 30 minutes, has zero area: a strip of zero width. That's why continuous probabilities are always asked about ranges, such as "between 25 and 35 minutes", and never about one exact value.
Show the answer
About 68%
The area under the normal curve between one standard deviation below and above the mean is about 0.68. Within two it's about 95%, and within three about 99.7%.
Integrals undo derivatives
Keep a running total of a rate, and you get a curve of the total so far. Its slope at any moment is the rate at that moment: the total grows fast when the rate is high, and stays flat when the rate is zero. So the derivative of a running total gives back the rate, and the integral of a rate gives the total. They undo each other, which is the fundamental theorem of calculus. It also gives a shortcut: the area between a and b is just the running total at b minus the running total at a, so one running total answers every "how much between these two points?".
rates = [2, 3, 5, 0, 4] # sign-ups per hour totals = [] running = 0 for r in rates: running += r totals.append(running) print(totals) print([totals[0]] + [totals[i] - totals[i - 1] for i in range(1, len(totals))]) # differences give the rates back
rates = [2, 3, 5] running = 0 totals = [] for r in rates: running += r totals.append(running) print(totals)
Show the answer
[2, 5, 10]
The running total adds each rate in turn: 2, then 2 + 3 = 5, then 5 + 5 = 10. The differences between neighbors give back the rates.
AUC from ROC points
A classifier's ROC curve passes through these (false positive rate, true positive rate) points, in order. Set auc to the area under it with trapezoids: for each pair of neighboring points, (x₂ − x₁) × (y₁ + y₂) / 2.
roc = [(0.0, 0.0), (0.1, 0.5), (0.3, 0.8), (0.6, 0.95), (1.0, 1.0)] auc = 0 print(round(auc, 4))
Integrals in AI
AUC is the area under the ROC curve, computed exactly this way from the points a classifier's thresholds trace out. The expected value of a continuous quantity is an integral: each value times its density, added up. A cumulative distribution, the chance of a value at or below x, is the running area under a density. Training compute is the integral of power over time, and charts of a model's performance often report the area under a learning curve to sum up how fast and how far it learned. Whenever you see "total", "area" or "cumulative", look for a rate being added up.
In many dimensions, strips stop working: a grid fine enough to cover 50 dimensions would have more cells than there are atoms in the world. There, integrals are estimated by averaging random samples instead, a Monte Carlo method, which is the same trick the bootstrap and the simulations in this phase use.
Show the answer
0.5: no better than random guessing
The diagonal splits the unit square in half, so the area under it is 0.5. That's what random scores give: a positive is ranked above a negative only half the time.
Practice what you just read
- 4 code examples you can edit and run
- a practice exercise that checks your code
- a 6-question quiz
- 5 review cards for spaced repetition
Try a quiz question
What does the integral of a rate over a time range give you?