Code
Mon 8123
Tue 10450
Wed 9800
Name: steps, dtype: int64
CSCI 1109 — Practical Data Science
Note
In most real data work, although fancy ML models may be your focus, to train those models correctly will require a fair amount of ‘data wrangling’ of the type we talk about here.
By the end of this module, you should be able to:
.head(), .shape, .columns, and .index to quickly inspect a DataFrame.Real projects you might work on:
trip_id, start_time, end_time, start_station, end_station, user_type, price.patient_id, date, systolic_bp, diastolic_bp, heart_rate.user_id, date, steps, sleep_hours, city.All of these are tables: rows are records, columns are variables.
Tip
pandas gives us a language for working with tables in Python.
pandas.Series → 1D, labelled vector of values.pandas.DataFrame → 2D, table made of aligned Series.Mon 8123
Tue 10450
Wed 9800
Name: steps, dtype: int64
Note
For now: think “Series = column with labels”, “DataFrame = whole table”.
| user_id | city | steps | |
|---|---|---|---|
| 0 | 101 | Halifax | 8123 |
| 1 | 102 | Halifax | 10450 |
| 2 | 103 | Toronto | 9800 |
We can quickly inspect:
| user_id | city | steps | |
|---|---|---|---|
| 0 | 101 | Halifax | 8123 |
| 1 | 102 | Halifax | 10450 |
| 2 | 103 | Toronto | 9800 |
Tip
When you get a new dataset, your first moves should feel like saying hello: look at .head(), .shape, .columns, and .dtypes (more on dtypes in M08).
steps is a Series: just one column of data with an index.df_steps is a DataFrame: still one column, but:
✏️
When is it enough to use a Series, and when do I want a full DataFrame?
Tidy data (from 🔗 Hadley Wickham):
- Each variable → a column.
- Each observation → a row.
- Each type of observational unit → a table.
Example (daily app data):
Tidy:
| user_id | date | city | steps | sleep_hours |
|---|---|---|---|---|
| 101 | 2025-09-01 | Halifax | 8123 | 7.5 |
| 102 | 2025-09-01 | Halifax | 10450 | 6.8 |
| 101 | 2025-09-02 | Halifax | 9800 | 7.9 |
Messy example (wide):
| user_id | city | steps_2025_09_01 | steps_2025_09_02 | sleep_1 | sleep_2 |
|---|---|---|---|---|---|
| 101 | Halifax | 8123 | 9800 | 7.5 | 7.9 |
| 102 | Halifax | 10450 | NaN | 6.8 | NaN |
Warning
Both tables contain the same information, but tidy tables are much easier to: - filter, - group, - visualise, - and feed into models.
Imagine a campus study:
A tidy table might look like:
| student_id | date | program | year | sleep_hours | stress_level |
|---|---|---|---|---|---|
| 201 | 2025-09-01 | CS | 1 | 6.0 | 7 |
| 201 | 2025-09-02 | CS | 1 | 7.5 | 5 |
| 305 | 2025-09-01 | Biology | 2 | 8.0 | 3 |
Questions we can answer easily from tidy data:
In later modules, we’ll use pandas to actually run these summaries.
| user_id | steps_mon | steps_tue | steps_wed | |
|---|---|---|---|---|
| 0 | 101 | 8123 | 9800 | 7500 |
| 1 | 102 | 10450 | 9000 | 10100 |
| 2 | 103 | 9800 | 12050 | 11500 |
This is nice for one person per row, but awkward if we want:
| user_id | day | steps | |
|---|---|---|---|
| 0 | 101 | steps_mon | 8123 |
| 1 | 102 | steps_mon | 10450 |
| 2 | 103 | steps_mon | 9800 |
| 3 | 101 | steps_tue | 9800 |
| 4 | 102 | steps_tue | 9000 |
| 5 | 103 | steps_tue | 12050 |
| 6 | 101 | steps_wed | 7500 |
| 7 | 102 | steps_wed | 10100 |
| 8 | 103 | steps_wed | 11500 |
Now we have:
(user_id, day),steps column.We’ll get more systematic about reshaping in M10, but it’s useful to see the idea now.
temp_morning, temp_afternoon, temp_evening, what might a tidy version look like?Note
You don’t need to memorise every pandas method yet; just make sure the concept of tidy tables feels clear.
describe(), info(), data types.groupby, aggregations, windows, pivots and reshaping.Your job after this module:
