Why start here
In a spreadsheet you can see your data the moment you open the file. In pandas you see it only after you write code to load or build it. It feels odd at first. The payoff is that every step you take gets written down, and you can run the whole thing again next month with a fresh export. In this level you'll set up a notebook, check your pandas version and build two structures by hand: the Series, which is like one labelled column, and the DataFrame, which is like a sheet. Once you understand how these two map to columns, rows and row labels, everything later in the course is easier.
Step 1: Get a notebook running
A notebook is a document made of cells. Each cell holds code that you run on its own, and the output shows up underneath. That makes it feel like a spreadsheet: you change something and see the result straight away.
Option A: JupyterLab in the browser
# In a terminal (PowerShell, Terminal, etc.)
python -m pip install jupyterlab pandas # installs JupyterLab and pandas
python -m jupyter lab # opens JupyterLab in your browser
The python -m form makes sure you use the same Python that you installed into. It also avoids many "jupyter is not recognized" PATH errors on Windows.
Option B: VS Code
- Install the Jupyter extension (and the Python extension, if you don't have it).
- Install pandas and
ipykernelinto the Python environment you want to use:python -m pip install pandas ipykernel. VS Code needs onlyipykernelto run Python as a notebook kernel. You don't need the full Jupyter package. - Press Ctrl+Shift+P and run Create: New Jupyter Notebook, or just create a file ending in
.ipynb. - Click Select Kernel at the top right and pick that environment.
To run a cell, press Shift+Enter. That runs the cell and moves you to the next one. Ctrl+Enter runs the cell and leaves you where you are.
Gotcha: if
import pandassaysModuleNotFoundError, the kernel is almost always a different Python from the one you installed pandas into. Check which kernel is selected before you reinstall anything.
Step 2: Import pandas and check the version
import pandas as pd # 'pd' is the universal convention; use it
print(pd.__version__) # e.g. '3.0.6' or '2.2.3'
This matters because pandas 3.0 (released January 2026) changed some default behaviour that this course will point out as it comes up. The change you'll see first: in pandas 3.0, text columns get a dedicated str dtype, while in pandas 2.x they show as object. Copy-on-Write also became the default in 3.0. It affects how changes to a subset behave, and we'll deal with it when we start modifying data. pandas 3.0 needs Python 3.11 or later.
In every new analysis, put the version print in the first cell. If someone else gets different results, the version is the first thing you'll compare.
Step 3: A Series is one labelled column
# Monthly sales by region, as a plain Python dict
sales = pd.Series({"North": 1200, "South": 950, "East": 1430}, name="sales")
sales
North 1200
South 950
East 1430
Name: sales, dtype: int64
There are three parts to read here:
- Index: the labels on the left (
North,South,East). When you build a Series from a dict, the keys become the index. - Values: the numbers on the right.
- dtype: one data type for the whole Series, here
int64(whole numbers).
sales.index # Index(['North', 'South', 'East'], dtype='str') (dtype='object' on 2.x)
sales.dtype # dtype('int64')
In spreadsheet terms, a Series is like column B with column A's labels permanently attached. If you sort or filter the values, each label stays with its value.
Step 4: A DataFrame is a sheet of Series
Pass a dict of lists to build a DataFrame. Each key becomes a column header, and each list becomes that column's values.
invoices = pd.DataFrame({
"invoice_id": ["INV-001", "INV-002", "INV-003"],
"customer": ["Acme Ltd", "Brightwater", "Cole & Co"],
"amount": [1200.0, 950.5, 1430.0],
"paid": [True, False, True],
})
invoices
invoice_id customer amount paid
0 INV-001 Acme Ltd 1200.0 True
1 INV-002 Brightwater 950.5 False
2 INV-003 Cole & Co 1430.0 True
The 0, 1, 2 on the left is the index. You didn't supply one, so pandas made a default RangeIndex that counts from 0. Let's inspect each part:
invoices.index # RangeIndex(start=0, stop=3, step=1)
invoices.columns # Index(['invoice_id', 'customer', 'amount', 'paid'], dtype='str')
invoices.dtypes
invoice_id str <- 'object' on pandas 2.x
customer str <- 'object' on pandas 2.x
amount float64
paid bool
dtype: object
(That last dtype: object line describes the list of dtypes itself. You can ignore it.)
In a spreadsheet the row labels are fixed row numbers. In pandas you can supply meaningful row labels instead:
invoices_by_id = pd.DataFrame(
{"customer": ["Acme Ltd", "Brightwater", "Cole & Co"],
"amount": [1200.0, 950.5, 1430.0]},
index=["INV-001", "INV-002", "INV-003"], # row labels instead of 0, 1, 2
)
All the lists must be the same length. If they aren't, pandas raises a ValueError and won't guess.
How this differs from a spreadsheet range
| Spreadsheet | pandas DataFrame |
|---|---|
| Any cell can hold anything | One dtype per column |
| Rows are numbered 1, 2, 3 by position | Rows have an index, which can be meaningful labels |
| Headers are just the first row of data | Column names are separate from the data |
| Formulas live in cells | Calculations live in code you can rerun |
One dtype per column has a cost when your data is messy:
pd.Series([100, "n/a", 250]).dtype # dtype('O') -> object: mixed types
One stray "n/a" turns the whole column into object, so it's no longer numeric, and maths on it will fail or behave oddly. In a spreadsheet that cell would just sit there quietly. pandas makes the problem show up in the dtype, which is useful. Get into the habit of checking .dtypes.
Check your work
Run this cell. It should print True three times:
print(list(invoices.columns) == ["invoice_id", "customer", "amount", "paid"])
print(invoices["amount"].dtype == "float64")
print(list(sales.index) == ["North", "South", "East"])
Key takeaways
- A notebook runs code in cells. Use Shift+Enter, and make sure the kernel is the Python where pandas is installed.
- Put
print(pd.__version__)in your first cell. On 3.0 text columns show asstr, on 2.x asobject. - A Series is one column with an index and a single dtype. Built from a dict, its keys become the index.
- A DataFrame is a table of columns. A dict of lists gives you column names from the keys and a default 0-based
RangeIndex. - Unlike a spreadsheet, each column has one dtype, and rows have an index of labels, not just positions.