Python foundations for AI
Hookโ
You follow a tutorial that fits a model in one line: model.fit(X, y). It works
on the tutorial's data, so you point it at your own spreadsheet and it explodes
with could not convert string to float. The tutorial never showed you what X
and y actually are, so when your data does not already look like theirs, you
are stuck. Every model in this school expects the same two shapes, and once you
can build them from raw records, the rest stops being magic.
Conceptโ
A machine-learning model does not see rows, columns, or spreadsheets. It sees two
things: a list of feature vectors โ the numeric inputs for each example,
conventionally called X โ and a matching list of labels โ the answer for
each example, conventionally called y. A feature vector is simply an ordered
group of numbers describing one example; the label is what you want to predict
for it. Getting from raw data to a clean (X, y) pair is most of the work, and
Python's built-in structures are the tools for it.
You already met these structures in a general context; here is what each one does in the shape of ML data:
- A list holds the examples in order โ
Xis a list of feature vectors,yis a list of labels, and positioniin one lines up with positioniin the other. - A tuple is a natural feature vector:
(tenure_months, monthly_charges)is a fixed, ordered group of numbers you never mutate. - A dict is how a raw record usually arrives โ a CSV or JSON reader hands you
{"tenure_months": "2", "monthly_charges": "89.0"}, with keys naming columns and values still as strings. - A list comprehension is how you pull one column out of many rows, and
zipis how you walkXandytogether without index bookkeeping.
The move you will make constantly is turning a list of raw dicts into X and
y. Read a feature out of each dict, coerce it to a number, and collect the
results:
# A dataset is rows; each row pairs a feature vector with a label.
dataset = [
({"tenure_months": 2, "monthly_charges": 89.0}, "churn"),
({"tenure_months": 40, "monthly_charges": 55.0}, "stay"),
({"tenure_months": 8, "monthly_charges": 95.0}, "churn"),
]
X = [(row["tenure_months"], row["monthly_charges"]) for row, _ in dataset]
y = [label for _, label in dataset]
print(X)
print(y)
[(2, 89.0), (40, 55.0), (8, 95.0)]
['churn', 'stay', 'churn']
The rule that holds across the whole school: X and y are two aligned
sequences, one feature vector and one label per example, and keeping them aligned
is your job. Every model, metric, and split in this course assumes that
alignment; break it and you will train on one example's features against another
example's answer.
| Structure | Its job in ML data | Example |
|---|---|---|
| list | Ordered collection of examples (X and y) | [(2, 89.0), (40, 55.0)] |
| tuple | One feature vector: fixed, ordered numbers | (2, 89.0) |
| dict | A raw record at the input boundary | {"tenure_months": "2"} |
| comprehension | Extract a feature or label column from rows | [r["plan"] for r in records] |
Worked exampleโ
Let me turn a batch of raw usage records into X and y for a task that
predicts a user's plan from their activity. The records arrive as dicts with
everything as strings โ the typical output of a CSV reader โ and I want feature
vectors of (sessions, minutes) paired with the plan label.
raw_records = [
{"id": "u-1", "sessions": "12", "minutes": "240", "plan": "pro"},
{"id": "u-2", "sessions": "3", "minutes": "35", "plan": "free"},
{"id": "u-3", "sessions": "9", "minutes": "180", "plan": "pro"},
]
X = [(int(r["sessions"]), int(r["minutes"])) for r in raw_records]
y = [r["plan"] for r in raw_records]
for features, label in zip(X, y):
print(features, "->", label)
mean_sessions = sum(sessions for sessions, _ in X) / len(X)
print("mean sessions:", round(mean_sessions, 2))
(12, 240) -> pro
(3, 35) -> free
(9, 180) -> pro
mean sessions: 8.0
Three decisions in that small block matter. First, I dropped id from the
feature vector on purpose: an identifier carries no signal a model should learn
from, and feeding it in invites the model to memorize rows. Second, I cast
sessions and minutes with int(...) right where I build the vector, so
nothing downstream ever sees a string where it expects a number. Third, I used
zip(X, y) to walk the aligned pair together โ no range(len(X)) index juggling,
and the alignment is obvious to anyone reading it. The mean at the end is a first
taste of the summary statistics you will lean on in the next lesson.
Hands-onโ
Your turn, with a different dataset. The exercise below hands you raw sensor
records as dicts and asks you to build X as a list of (temperature, humidity)
tuples and y as the list of state labels, coercing the numeric fields as you
go. It runs in Python Arena, so there is nothing to install.
Success criteria: your code returns X and y as aligned sequences of the same
length, with each feature vector a tuple of two numbers and each label a string.
The Arena checks the alignment and types against a hidden set of records
automatically.
Recapโ
- You can describe any supervised dataset as
X(feature vectors) andy(aligned labels), one entry per example. - You can turn a list of raw dicts into
Xandy, coercing string fields to numbers and dropping identifiers that carry no signal. - You can walk the aligned pair with
zipinstead of index bookkeeping, keeping features and labels lined up.
Next up: where those rows come from. You will load a real dataset from a CSV file and describe it with summary statistics before you trust it.
- A supervised dataset is two aligned sequences: X (feature vectors) and y (labels). - Raw records arrive as dicts of strings; extract and coerce fields to build numeric feature vectors. - Keep X and y aligned with zip, and keep identifiers out of the features.