Series and DataFrame
A NumPy array knows positions, but a real sales log has names: a date, a branch, a genre. pandas adds those labels. From here on, the bookshop's eight sales live in one table called sales, and every lesson asks it a new question.
The rule
A Series is one labelled column; a DataFrame is Series sharing one index.
import pandas as pd
sales = pd.DataFrame({
"date": ["2024-03-01", "2024-03-01", "2024-03-02", "2024-03-02",
"2024-03-03", "2024-03-03", "2024-03-04", "2024-03-04"],
"branch": ["Pune", "Delhi", "Pune", "Chennai",
"Delhi", "Chennai", "Pune", "Delhi"],
"genre": ["fiction", "science", "science", "fiction",
"fiction", "comics", "comics", "science"],
"copies": [3, 5, 2, 4, 1, 6, 2, 3],
"price": [250, 400, 400, 250, 250, 120, 120, 400],
})| date | branch | genre | copies | price | |
|---|---|---|---|---|---|
| 0 | 2024-03-01 | Pune | fiction | 3 | 250 |
| 1 | 2024-03-01 | Delhi | science | 5 | 400 |
| 2 | 2024-03-02 | Pune | science | 2 | 400 |
| 3 | 2024-03-02 | Chennai | fiction | 4 | 250 |
| 4 | 2024-03-03 | Delhi | fiction | 1 | 250 |
| 5 | 2024-03-03 | Chennai | comics | 6 | 120 |
| 6 | 2024-03-04 | Pune | comics | 2 | 120 |
| 7 | 2024-03-04 | Delhi | science | 3 | 400 |
The numbers on the left, 0 to 7, are the index: a label for each row. Every column is a Series, a 1-D array with that same index attached.
sales["copies"] # a Series
sales[["branch", "copies"]] # a DataFrame with two columns
sales.shape # (8, 5)
sales.dtypes # the type of each column
sales.head(3) # first three rows
sales.describe() # count, mean, min, max... for number columnsEach column keeps its own dtype, so a DataFrame can mix text and numbers while each column stays fast underneath.
New columns come from whole-column arithmetic, just like NumPy:
sales["revenue"] = sales["copies"] * sales["price"]The shortcut
Count the brackets: single brackets give a Series, double brackets give a DataFrame. The inner pair in [["copies"]] is a list of column names, and a list always means "a table of these columns".
Pick the inputs
sales["copies"]andsales["price"]are two Series with the same index 0 to 7.
The trap: pandas lines values up by index label, not by position. Two Series with different indexes produce NaN where labels do not match, which can look like missing data you never had.
Drills
Answer fast — trust the rule.
What does sales["branch"] return?
What is sales[["genre"]].shape for the eight-row table?
What is the revenue value in row 5?
Series a has index [0, 1, 2] and b has index [1, 2, 3]. How many NaN values does a + b contain?
Remember
- A Series is one labelled column; a DataFrame is Series sharing one index.
- Single brackets → Series; double brackets → DataFrame.
- Arithmetic lines up by index label, and unmatched labels become NaN.
