The idea
pandas is the Python library data analysts use to work with tables. Think of it as a spreadsheet you control with code: you can load data, clean it, calculate new columns and summarise it, and then run the exact same steps again next month with one click. No more redoing a report by hand.
Everything in pandas is built from two objects:
- a Series: one column of values, with a label for each value
- a DataFrame: a table made of several Series that share the same row labels
Learn these two well and the rest of pandas becomes "which method do I call on my DataFrame?".
By convention, everyone imports pandas with the short name pd. You'll see this line at the top of almost every data script in the world:
import pandas as pd
The Series: one labelled column
A Series is one column of data, like the price column of a product list. The easiest way to make one is from a plain Python list of values:
import pandas as pd
prices = pd.Series([95000, 65000, 110000])
print(prices)
0 95000
1 65000
2 110000
dtype: int64
There are two columns in that output, but only one holds your data. The numbers on the left (0, 1, 2) are the index: the label of each value. pandas adds a numbered index for you if you don't give one. At the bottom, dtype: int64 is the data type, meaning every value is a 64-bit whole number. A Series always has one dtype for all its values, which is what makes it fast.
Numbered labels are fine, but meaningful labels are better. Pass your own with index=:
prices = pd.Series(
[95000, 65000, 110000],
index=["Arabica Gayo", "Robusta Lampung", "Toraja Kalosi"],
)
print(prices)
print(prices["Toraja Kalosi"])
Arabica Gayo 95000
Robusta Lampung 65000
Toraja Kalosi 110000
dtype: int64
110000
Now you can look up a value by its label, like a dictionary. This is the key difference from a Python list: a Series knows what each value means.
Maths on the whole column at once
The real power shows up when you do maths. An operation on a Series applies to every value, no loop needed:
with_tax = prices * 1.11
print(with_tax)
Arabica Gayo 105450.0
Robusta Lampung 72150.0
Toraja Kalosi 122100.0
dtype: float64
This is called a vectorised operation. It's shorter than a loop, easier to read, and much faster on large data. Notice the dtype changed to float64, since multiplying by a decimal gives decimals.
The DataFrame: a whole table
A DataFrame is what you'll use most of the time. The easiest way to build one by hand is from a dictionary of lists: each key becomes a column name, and each list becomes that column's values.
orders = pd.DataFrame({
"product": ["Arabica Gayo", "Ceramic Mug", "French Press", "Robusta Lampung"],
"quantity": [3, 2, 1, 4],
"unit_price": [95000, 55000, 185000, 65000],
})
print(orders)
product quantity unit_price
0 Arabica Gayo 3 95000
1 Ceramic Mug 2 55000
2 French Press 1 185000
3 Robusta Lampung 4 65000
Every list must have the same length, because each position is one row. A few attributes tell you about the table's shape:
print(orders.shape) # (rows, columns)
print(orders.columns) # the column names
print(orders.dtypes) # the type of each column
(4, 3)
Index(['product', 'quantity', 'unit_price'], dtype='object')
product object
quantity int64
unit_price int64
dtype: object
object is pandas' name for "general Python objects", which for now means text. Notice that shape has no brackets after it: it's an attribute (a stored fact), not a method you call.
On this site you can use display(orders) instead of print(orders) to show a DataFrame as a proper table, the way Jupyter notebooks do. Both work.
A column is a Series
Pick one column with square brackets and its name. What comes back is a Series:
print(orders["quantity"])
0 3
1 2
2 1
3 4
Name: quantity, dtype: int64
That's the mental model: a DataFrame is a set of Series glued together by a shared index. Everything you can do to a Series, you can do to a column.
Adding a calculated column
To add a column, assign to a new name. Because columns are Series, the maths is vectorised across every row:
orders["revenue"] = orders["quantity"] * orders["unit_price"]
print(orders)
product quantity unit_price revenue
0 Arabica Gayo 3 95000 285000
1 Ceramic Mug 2 55000 110000
2 French Press 1 185000 185000
3 Robusta Lampung 4 65000 260000
pandas multiplied row 0 by row 0, row 1 by row 1, and so on. In a spreadsheet you'd write a formula in the first cell and drag it down. Here, one line does every row.
Quick summaries
Once you have a column, the first questions are usually the same: what's the total, what's the average, what's the biggest? Every Series has built-in methods that answer them directly, with no loop needed:
print(orders["revenue"].sum()) # 840000
print(orders["revenue"].mean()) # 210000.0
print(orders["unit_price"].max()) # 185000
Other useful ones are .min(), .count() and .round(1), which rounds every value to one decimal place. You'll meet many more in the coming modules.
Column names are case-sensitive and must match exactly. orders["Quantity"] raises a KeyError because the column is called quantity. When you get a KeyError, print orders.columns and compare.
Why this matters for clean code
Two habits start here. First, name DataFrames after what they hold: orders, customers, daily_sales. Code full of df, df2 and df_final is impossible to follow a week later. Second, prefer vectorised operations over loops. orders["quantity"] * orders["unit_price"] says exactly what you mean in one line, and runs fast on a million rows.
Recap
import pandas as pdis the standard import.- A Series is one column of values with an index (labels) and one dtype.
- A DataFrame is a table: several Series sharing an index. Build one from a dictionary of lists.
df["col"]gives you a column as a Series.df["new"] = ...adds a column.- Maths on a Series applies to every value at once (vectorised).
.shape,.columnsand.dtypesdescribe a DataFrame..sum(),.mean(),.max()summarise a column.