Index Ai Academy
Phase 2 · Math, when you need it · Calculus

Integrals: totals and areas

Totals from rates, areas from thin strips, probability as area, and AUC by trapezoids.

About 25 minutes · A free account opens the whole lesson

Create a free account Try part of it here

Already have an account? Sign in to open this lesson

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

  1. Totals from rates
  2. Smooth curves: thinner and thinner strips
  3. The trapezoid rule
  4. Probability is area
  5. Integrals undo derivatives
  6. AUC from ROC points
  7. Integrals in AI
Quick check
Before any explaining, a guess. A delivery van drives at 60 km/h for 2 hours, then at 30 km/h for 1 hour. How far does it go?
  1. 45 km
  2. 150 km
  3. 90 km
  4. 180 km
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")
It runs right here in your browser, with nothing to install.

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.

Quick check
A server handled requests at these rates, one value per minute. What does this print?
per_second = [10, 12, 15, 11]
print(sum(rate * 60 for rate in per_second))
  1. 4800
  2. 720
  3. 2880
  4. 48
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.

Try it now

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.

Quick check
Why do more, thinner strips give a better estimate of the area under a curve?
  1. Thinner strips are taller, so they cover more area
  2. The curve becomes straighter as strips get thinner
  3. More strips always overestimate, which balances out
  4. Each strip's flat top fits the curve more closely
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.

Drill

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)
In the lesson, your code is checked as you write it.

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.

Quick check
As in the normal distribution lesson: about what share of a normal distribution lies within one standard deviation of its mean?
  1. About 68%
  2. About 50%
  3. About 99.7%
  4. About 95%
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
Quick check
What does this print?
rates = [2, 3, 5]
running = 0
totals = []
for r in rates:
    running += r
    totals.append(running)
print(totals)
  1. [2, 5, 10]
  2. [2, 6, 30]
  3. [10]
  4. [2, 3, 5]
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.

Drill

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))
In the lesson, your code is checked as you write it.

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.

Quick check
A classifier's ROC curve is the straight diagonal from (0, 0) to (1, 1). What is its AUC?
  1. 0.0: it's always wrong
  2. 0.5: no better than random guessing
  3. 0.25: a quarter of the square
  4. 1.0: it ranks every case perfectly
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

Create a free account

Try a quiz question

What does the integral of a rate over a time range give you?

  1. The total accumulated over that range
  2. The rate at the end of the range
  3. How fast the rate is changing
  4. The average of the start and end rates

Answer it at the end of the lesson to see if you're right, and why.

Before this lesson