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

Functions and graphs

Read a graph and see how an output depends on an input.

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

A trained model is a function. Text goes in and probabilities come out. Its loss (one number that says how wrong it is) is a function too, this time of its weights, the numbers it learns. Training is a search for the lowest point on that function's graph. Marketing is full of functions as well: revenue depends on price, and conversions depend on ad spend. This lesson teaches you to look at a graph and say "this flattens out" or "this peaks here". The lessons that follow, on derivatives (a derivative is the exact slope of a graph at a point), turn that habit into exact tools.

What you'll be able to do

  • Read function notation and evaluate functions on whole arrays of inputs
  • Read a graph: where it rises, falls, flattens and peaks
  • Recognize the shapes that recur in machine learning: line, bowl, S-curve, hinge
  • Find the best input for a function by evaluating many candidates

What it covers

  1. Inputs to outputs
  2. From a function to a graph
  3. A marketing function: diminishing returns
  4. Finding the best budget
  5. Shapes you'll keep meeting
  6. Worked example: four shapes, three inputs

Inputs to outputs

Think of a vending machine. You press B4 and out comes one particular snack. Press B4 again tomorrow and you get the same snack. One button never gives you two snacks, and it never gives you a random one.

A function works the same way. It takes an input and gives back exactly one output. Same input, same output, every time.

You already write functions in Python with def. Math writes them in a short form:

f(x)=x2f(x) = x^2

Here ff is the function's name, like the name after def. The letter xx stands for the input. Then x2x^2 means xx times xx, called "x squared".

In plain words: "f of x equals x squared." Whatever number you put in, multiply it by itself to get the output.

Try some small numbers. Put in 3 and you get 3 × 3 = 9. Put in 0 and you get 0. Put in −2 and you get (−2) × (−2) = 4, because a negative times a negative is positive. The same thing in Python:

def f(x):
    return x ** 2

print(f(3), f(0), f(-2))
It runs right here in your browser, with nothing to install.

It prints 9 0 4.

Some functions only accept certain inputs. The inputs a function accepts are called its domain. A square root, for instance, only accepts x≥0x \geq 0 (zero or more) when you work with ordinary numbers. No ordinary number times itself gives −4, so −4 has no square root.

Quick check
What does this print?
def sales(ad_spend):
    return 100 + 3 * ad_spend
print(sales(10) - sales(0))
  1. 100
  2. 30
  3. 3
  4. 130
Show the answer

30

A slope of 3 means 3 more sales per dollar, so 10 dollars adds 30.

Quick check
With f(x) = x², what is f(−3)?
  1. −6
  2. −9
  3. 9
  4. 6
Show the answer

9

(−3) × (−3) = 9. Squaring a negative number gives a positive one.

From a function to a graph

A long list of inputs and outputs is hard to read at a glance. A picture is easier. The graph of a function draws each input and its output as a dot: input across, output up. Math writes each dot as (x,f(x))(x, f(x)): first how far across, then how far up.

For f(x)=x2f(x) = x^2 the dots include (−2, 4), (0, 0) and (3, 9). Draw enough dots and they join into a smooth U-shaped curve.

NumPy makes this quick. Hand it a whole array of inputs and one call works out every output at once. That's how you draw a graph: pick many inputs, compute the outputs, plot them.

import numpy as np
import matplotlib.pyplot as plt

def f(x):
    return x ** 2

x = np.linspace(-3, 3, 200)        # 200 evenly spaced inputs
plt.plot(x, f(x))
plt.title("f(x) = x²")
print(f(3), f(np.array([-2, 0, 2])))

np.linspace(-3, 3, 200) makes 200 evenly spaced inputs from −3 to 3. The plot shows the U. The printout is 9 [4 0 4]. One input gives one output. An array of inputs gives an array of outputs.

A marketing function: diminishing returns

Think about cups of coffee. The first one in the morning makes a big difference. The second helps a little. By the fifth you feel almost nothing extra. Each cup adds less than the one before. That pattern is called diminishing returns.

Ad spend often behaves the same way. The first dollars reach the people most likely to buy. Later dollars reach people who care less. So conversions (sales or sign-ups from the ads) don't grow in a straight line with spend. They climb fast, then level off toward a ceiling.

A common model for this is a saturating curve:

c(s)=cmax⁡⋅ss+kc(s) = c_{\max} \cdot \frac{s}{s + k}

Take the symbols one at a time:

  • ss is the monthly ad spend in dollars. It's the input.
  • c(s)c(s) is the number of conversions you get for that spend. It's the output.
  • cmax⁡c_{\max}, said "c max", is the ceiling: the level conversions creep toward but never quite reach.
  • kk is the spend at which you reach half the ceiling.
  • The dot ⋅\cdot means multiply.

In plain words: divide your spend by (spend plus k). That gives a fraction between 0 and 1. Multiply the fraction by the ceiling to get your conversions.

Here's a worked example. Say the ceiling is 900 conversions and k is $4,000.

SpendFraction s / (s + k)Conversions
$00 / 4,000 = 00
$4,0004,000 / 8,000 = 0.5450
$8,0008,000 / 12,000 ≈ 0.67600
$12,00012,000 / 16,000 = 0.75675

The first $4,000 brings 450 conversions. The next $4,000 brings only 150 more. The $4,000 after that brings 75 more. Each step buys less. The same calculation in Python:

def conversions(spend, c_max=900, k=4000):
    return c_max * spend / (spend + k)

for spend in [0, 4000, 8000, 12000]:
    print(spend, conversions(spend))

Next to each spend it prints the table's last column: 0.0, 450.0, 600.0 and 675.0.

Go deeper Why k is the halfway point

Set the spend equal to kk. The fraction becomes kk+k=k2k=12\frac{k}{k + k} = \frac{k}{2k} = \frac{1}{2}. So c(k)=cmax⁡/2c(k) = c_{\max} / 2, half the ceiling, whatever the numbers are.

The fraction never quite reaches 1, because the bottom (s+ks + k) is always bigger than the top (ss). That's why the curve creeps closer and closer to the ceiling without touching it.

Finding the best budget

More conversions isn't the same as more profit. Say each conversion earns you $60 of margin, which is what's left after costs. Then your profit is that margin minus what you spent on ads:

profit = 60 × conversions − spend

Use the numbers from the table. At $4,000 of spend, profit is 60 × 450 − 4,000 = $23,000. At $12,000 it's 60 × 675 − 12,000 = $28,500. Spend a lot more and profit drops again, because the extra conversions no longer cover the extra spend.

The code below tries 300 budgets from $0 to $30,000. It works out the profit for each and keeps the best one.

import numpy as np
import matplotlib.pyplot as plt

def conversions(spend, c_max=900, k=4000):
    return c_max * spend / (spend + k)

spend = np.linspace(0, 30000, 300)
profit = 60 * conversions(spend) - spend            # $60 margin per conversion, minus spend
best = spend[np.argmax(profit)]
plt.plot(spend, conversions(spend), label="conversions")
plt.plot(spend, profit / 60, label="profit ÷ 60")
plt.axvline(best, linestyle="--", color="gray")
plt.xlabel("monthly ad spend ($)")
plt.legend()
print(f"best spend ≈ ${best:,.0f}, profit ≈ ${profit.max():,.0f}")

It prints a best spend of about $10,736 and a profit of about $28,606. np.argmax finds the position of the largest profit. Then spend[...] looks up the budget at that position.

Now read the graph. Conversions keep rising but flatten out. Profit rises, peaks, then falls. The dashed line marks the peak: the best budget.

Trying every candidate and keeping the best is called grid search. It's simple and reliable when there are one or two inputs. For an AI model it's hopeless. A model can have billions of weights, the numbers it adjusts while it learns. Try 10 values for each of 2 inputs and you need 10 × 10 = 100 tries. Try 10 values for each of a million weights and the count is 1 followed by a million zeros. That's why the next lessons need derivatives. They point toward better settings without trying them all.

Go deeper How close does the grid get?

The grid checks budgets about $100 apart (30,000 ÷ 299 ≈ 100.3). The true peak is near $10,697, which you'll be able to find exactly once you know derivatives. The grid's answer, $10,736, is the nearest budget it tried. A finer grid gets closer, but it costs more work.

Quick check
You grid-search 10 candidate values for each of 3 inputs. How many combinations do you try?
  1. 1,000
  2. 13
  3. 100
  4. 30
Show the answer

1,000

10 × 10 × 10 = 1,000. Each extra input multiplies the count by 10, which is why grid search falls apart with many inputs.

Shapes you'll keep meeting

A handful of shapes turn up again and again in machine learning, which is the craft of fitting such shapes to data. Once you can spot them, many formulas start to look familiar.

ShapeFormulaWhere it shows up
Linef(x)=ax+bf(x) = ax + blinear models, a neuron before the step called activation
Bowlf(x)=(x−2)2+1f(x) = (x - 2)^2 + 1loss functions: one lowest point
S-curve (sigmoid)σ(x)=11+e−x\sigma(x) = \frac{1}{1 + e^{-x}}turning a score into a probability between 0 and 1
Hinge (ReLU)max⁡(0,x)\max(0, x)the most common activation in neural networks

Line

In f(x)=ax+bf(x) = ax + b, the number aa sets how steep the line is. The number bb is the output when the input is 0.

In plain words: multiply the input by one fixed number, then add another.

With a = 2 and b = 1, input 2 gives 2 × 2 + 1 = 5, and input −2 gives −3.

Bowl

In plain words: subtract 2 from the input, square the result, then add 1.

Input 0 gives (0 − 2)² + 1 = 5. Input 2 gives 0 + 1 = 1, the lowest output there is. Any other input lands higher up the sides of the bowl. Training a model means looking for the bottom of a bowl like this one. Real loss bowls are bumpier, but the idea is the same.

Quick check
For the bowl (x−2)2+1(x - 2)^2 + 1, which input gives the lowest output?
  1. −2
  2. 2
  3. 1
  4. 0
Show the answer

2

At 2 the squared part is 0, so the output is 1. Any other input adds something positive.

S-curve (sigmoid)

The S-curve is called the sigmoid. Its name is written σ\sigma, the Greek letter sigma. The formula also uses ee, a fixed number about 2.718 that you'll meet properly in the next lesson.

In plain words: raise ee to the power of minus the input, add 1, then divide 1 by that. Big negative inputs give almost 0. Big positive inputs give almost 1. An input of 0 gives exactly 0.5.

Input 2 gives about 0.88. Input −2 gives about 0.12. That squashing is how a model turns any score into something that can be read as a probability.

Hinge (ReLU)

ReLU is short for "rectified linear unit". The max⁡(0,x)\max(0, x) part means "the larger of 0 and x".

In plain words: if the input is positive, keep it. If it's negative, output 0.

Input 2 gives 2. Input −2 gives 0.

Words for describing a graph

  • Increasing: the graph goes up as you move left to right.
  • Decreasing: it goes down.
  • Minimum: its lowest point. Maximum: its highest point.
  • Steep or flat: how fast the output changes as the input moves.

Steepness has a proper name, the derivative. It's coming next.

Quick check
ReLU is max(0, x). What does it give for x = −5 and for x = 3?
  1. −5 and 3
  2. 0 and 0
  3. 5 and 3
  4. 0 and 3
Show the answer

0 and 3

ReLU keeps positive inputs and turns negative ones into 0.

Worked example

Worked example: four shapes, three inputs

Put the inputs −2, 0 and 2 through each shape and compare. The line uses a = 2 and b = 1. Predict each row before you run it.

import math

def line(x):    return 2 * x + 1
def bowl(x):    return (x - 2) ** 2 + 1
def sigmoid(x): return 1 / (1 + math.exp(-x))
def relu(x):    return max(0, x)

for x in [-2, 0, 2]:
    print(x, line(x), bowl(x), round(sigmoid(x), 2), relu(x))
In the lesson you can change this and run it.

Each row is one input, then the line, bowl, sigmoid and ReLU outputs. The line rises by the same amount at every step: −3, 1, 5. The bowl falls from 17 to 5 to 1, its lowest point at x = 2. The sigmoid goes 0.12, 0.5, 0.88: always between 0 and 1, and exactly 0.5 at 0. ReLU gives 0 for −2 and 0, then 2 for 2.

Try it now

Three activation functions: sigmoid, ReLU and tanh, which is a cousin of the sigmoid and runs from −1 to 1. Drag the point along the sigmoid: big negative inputs give almost 0, big positive inputs almost 1, and 0 gives exactly 0.5.

Quick check
A graph of profit against price rises, peaks at $40, then falls. What does that tell you?
  1. Prices near $40 maximize profit; going higher or lower earns less
  2. $40 is the minimum profit
  3. Price has no effect on profit
  4. Profit always increases with price
Show the answer

Prices near $40 maximize profit; going higher or lower earns less

A peak is a maximum: moving away from it in either direction lowers the output.

Practice what you just read

  • 5 code examples you can edit and run
  • a practice exercise that checks your code
  • a 5-question quiz
  • 4 review cards for spaced repetition

Create a free account

Try a quiz question

Which function shape is typical of a loss function with one best setting?

  1. A bowl, with one lowest point
  2. A straight line, sloping down
  3. An S-curve, rising to a limit
  4. A flat line, the same everywhere

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

Before this lesson