Features and labels
Supervised learning: inputs, targets and predictions.
Create a free account Try part of it here
Why it matters
Most machine learning in business is supervised. It predicts which customers will leave, how much a customer will spend, or which team should answer a support ticket. Every one of those projects starts with three choices. You decide what one example is. You decide which columns the model may use as inputs. And you decide what answer it should predict. Get those wrong and the model looks brilliant in testing, then fails in real use. The usual culprit is the answer leaking into the inputs.
What you'll be able to do
- Name the parts of a supervised problem: examples, features, label, prediction
- Tell regression (predict a number) from classification (predict a category)
- Load a dataset into pandas and split it into X and y
- Spot leakage: features that wouldn't be known when the prediction is made
What it covers
- Learning from an answer key
- The model is a function
- Two kinds of target
- Working with pandas
- Leakage: the answer hiding in the inputs
- Worked example: set up a churn problem
Learning from an answer key
Think about how a child learns to name fruit. You hold up an apple and say "apple". You hold up a banana and say "banana". After enough examples, the child can name fruit you never showed them. Every example came with the right answer attached.
Supervised learning works the same way. You give the computer past examples, each with its answer. It learns to give answers for new examples on its own. The answers act like a teacher checking the work, which is where the name comes from.
The examples sit in a table, like a spreadsheet. Here are three customers from the dataset you'll load later in this lesson:
| tenure_months | orders_last_year | days_since_last_order | churned |
|---|---|---|---|
| 31 | 7 | 174 | 0 |
| 18 | 6 | 61 | 0 |
| 22 | 9 | 194 | 1 |
- Each row is one example. Here, one example is one customer.
- Some columns are features. These are the inputs: what you know about the customer. Here they are months as a customer (tenure), orders last year, and days since the last order.
- One column is the label, also called the target. It's the answer you want to predict.
"Churn" means a customer leaving. In this table, churned is 1 if the customer stopped buying in the next six months. It's 0 if they stayed. The model's guess for a row is its prediction.
Show the answer
Sale price
The label is the answer you want to predict. The other three are features: things you know before the house sells.
The model is a function
A model takes one row's features and gives back a prediction. It's like a recipe: ingredients go in, a dish comes out. In math you write it like this:
Take the symbols one at a time:
- , a bold x, is one row's features as a list of numbers. You met lists like this as vectors in Phase 2.
- is the model. It's a function that turns the features into an answer.
- , said "y-hat", is the prediction. The little hat marks a guess.
- with no hat is the true answer from the label column.
In plain words: feed one row's features into the model, and what comes out is the prediction.
Training means choosing the model so its guesses land close to the true answers. You train on examples where you already know those answers.
A worked example
Here's a very simple model. It predicts churn (1) when the last order was more than 90 days ago. Otherwise it predicts "stays" (0).
One customer placed 2 orders and last ordered 120 days ago. So . Since 120 is more than 90, the model's guess is . In fact this customer stayed, so . The guess was wrong. Training would adjust the model to make fewer mistakes like this one.
The same steps in Python:
def f(x): orders, days_since = x return 1 if days_since > 90 else 0 # 1 means "will churn" x = [2, 120] # one customer: 2 orders, 120 days since the last one y = 0 # what really happened: they stayed y_hat = f(x) print("prediction:", y_hat, "truth:", y, "right?", y_hat == y)
It prints prediction: 1 truth: 0 right? False.
X and y in code
A dataset has many rows, so code keeps them together. By custom, the whole table of features is called X, with one row per example. The whole column of labels is called y. You'll see these two names in almost every piece of machine learning code.
Go deeper Why a capital X and a bold y
Math has a habit for this. A capital letter like stands for a table of numbers, called a matrix. A bold lowercase letter like stands for a single list, called a vector. So holds every row's features, and holds every row's label. Row of is the for example number .
def f(days): return 1 if days > 90 else 0 print(f(30), f(200))
Show the answer
0 1
30 days is not more than 90, so the first guess is 0 (stays). 200 days is more than 90, so the second is 1 (churns).
Two kinds of target
"How much rain will fall tomorrow?" asks for a number. "Will it rain tomorrow?" asks for yes or no. The weather data is the same, but the question is a different kind. Machine learning splits targets the same way:
| Task | Target | Examples |
|---|---|---|
| Regression | a number | lifetime value, next month's spend, delivery time |
| Classification | a category | churn yes/no, lead quality A/B/C, ticket topic |
"Regression" is an old word from statistics. Here it means "predict a number". A category is one choice from a fixed list, such as yes or no, or A, B or C.
Classification with two classes, like churn yes or no, is called binary classification. It's the most common kind. These models usually don't give a bare yes or no. They give a probability for the "yes" class, like "72% likely to churn".
Watch out: a column of numbers isn't always a quantity. If regions are stored as 1, 2 and 3, region 3 isn't "three times" region 1. Those are categories that happen to use numbers as names.
The target decides which models and which scores you can use.
Show the answer
Classification
The answer is one choice from a fixed list of categories, so it's classification (with three classes).
Working with pandas
pandas is Python's spreadsheet library. A DataFrame is a table with named columns. It's the usual way to hold a dataset before you hand it to a model as NumPy arrays.
The code below fetches the course's practice dataset of 600 customers from the practice API. It loads them into a DataFrame and prints three things:
import pandas as pd import requests df = pd.DataFrame(requests.get("https://api.gradient.test/v1/customers").json()["data"]) print(df.shape) print(df[["tenure_months", "orders_last_year", "days_since_last_order", "churned"]].head()) print(df["churned"].value_counts())
df.shapeis the size of the table as (rows, columns): 600 customers and 14 columns..head()shows the first five rows of the columns you picked.value_counts()counts how often each value appears. 484 customers stayed (0) and 116 churned (1). That's about 19% who churned.
Next, choose the features and the label, and turn them into NumPy arrays:
import pandas as pd import requests df = pd.DataFrame(requests.get("https://api.gradient.test/v1/customers").json()["data"]) features = ["tenure_months", "orders_last_year", "avg_order_value", "days_since_last_order", "support_tickets", "trail_club"] X = df[features].to_numpy() y = df["churned"].to_numpy() print(X.shape, y.shape) print(df.groupby("churned")[features].mean().round(1))
Here's what each part does:
featuresis your list of input columns.trail_clubis 1 if the customer is in the loyalty program, and 0 if not..to_numpy()turns those columns into a NumPy array.Xhas shape (600, 6): one row per customer, one column per feature.yis thechurnedcolumn, 600 labels in a row. Its shape prints as (600,).groupby("churned")splits the customers into two groups: stayed and churned. Then.mean()averages each feature inside each group.
The group averages already hint at what a model will learn. Churners ordered less: about 3.6 orders last year, against 6.8 for those who stayed. Their last order was longer ago: about 157 days, against 70. And they filed more support tickets.
Leakage: the answer hiding in the inputs
Imagine a practice exam with the answer key printed faintly on the back of each page. You'd score 100%. Then the real exam arrives with no answer key, and you struggle. A model can fall into the same trap.
Here's the rule. A feature is allowed only if you'd know it at the moment you make the prediction. Breaking that rule is called leakage. It's the most common way machine learning projects fool themselves.
Say you predict who will churn next quarter. These features would leak:
- "number of orders next quarter" (it's the future),
- "received a win-back email" (sent because they churned),
- "account closed date" (only exists for churners),
- in this dataset,
lifetime_valueneeds a careful look. It's spend to date. That's fine if it's measured before the churn window starts. It leaks if it includes the months after.
A leaky model scores beautifully in testing, because the answer is in the inputs. Then it fails in production, meaning real use, where that information doesn't exist yet. When a model seems too good to be true, look for leakage first.
For marketers: the same trap shows up in attribution reports. A feature like "visited the order confirmation page" predicts purchase perfectly, and tells you nothing you can act on.
Show the answer
Whether the lead was invoiced
An invoice exists only after a purchase: it encodes the answer.
Worked example: set up a churn problem
Here are four past customers, stored as Python dictionaries. One field, winback_email, records whether the shop sent a "please come back" email. That email goes out because a customer has left, so it leaks the answer. Leave it out, build X and y, and check what kind of target you have.
# Four past customers. Each dictionary is one example (one row). customers = [ {"orders": 8, "days_since": 20, "tickets": 0, "winback_email": 0, "churned": 0}, {"orders": 2, "days_since": 150, "tickets": 3, "winback_email": 1, "churned": 1}, {"orders": 5, "days_since": 45, "tickets": 1, "winback_email": 0, "churned": 0}, {"orders": 1, "days_since": 200, "tickets": 2, "winback_email": 1, "churned": 1}, ] # winback_email is sent after a customer leaves, so it is left out features = ["orders", "days_since", "tickets"] X = [[c[f] for f in features] for c in customers] y = [c["churned"] for c in customers] print(len(X), "examples,", len(features), "features") print(X[1], "->", y[1]) print(sorted(set(y)))
It prints 4 examples, 3 features. X has one row per customer and one number per allowed feature. X[1] is the second customer, because Python counts from 0. That's 2 orders, 150 days since the last one, and 3 tickets, with the label 1 (churned). The labels hold only 0 and 1, so this is binary classification. Look back at winback_email: it matches churned in all four rows. A model given that field would score perfectly in testing and be useless in real use.
Practice what you just read
- 4 code examples you can edit and run
- a practice exercise that checks your code
- a 5-question quiz
- 4 review cards for spaced repetition
Try a quiz question
Predicting next month's spend in dollars is which kind of task?