DataFrame
A pandas DataFrame is a 2-D labelled table — rows + named columns, mixed dtypes per column. The Swiss-army workhorse of analytics: load, clean, transform, group, plot.
Create, inspect, select, mutate
EXAMPLE
import pandas as pd
import numpy as np
# 1) Create
# From a dict of columns
df = pd.DataFrame({
'name': ['Ada', 'Bo', 'Cy', 'Di'],
'age': [32, 28, 41, 22],
'city': ['Sydney', 'Sydney', 'Melbourne', 'Brisbane'],
})
# From a list of records
df = pd.DataFrame.from_records([
{'name': 'Ada', 'age': 32},
{'name': 'Bo', 'age': 28},
])
# From CSV / JSON / Parquet
df = pd.read_csv('users.csv', parse_dates=['signup_at'])
df = pd.read_json('users.json')
df = pd.read_parquet('users.parquet')
# 2) Inspect
df.head()
df.tail(3)
df.shape # (rows, cols)
df.columns
df.dtypes
df.info()
df.describe() # summary stats for numeric
df.memory_usage(deep=True)
# 3) Select columns
df['name'] # Series
df[['name', 'age']] # DataFrame
df.name # attribute access (only if name is a valid identifier)
# 4) Filter rows — boolean mask
df[df['age'] >= 30]
df[(df['age'] >= 30) & (df['city'] == 'Sydney')]
df[df['city'].isin(['Sydney', 'Brisbane'])]
df[df['name'].str.startswith('A')]
# 5) Position vs label
df.iloc[0] # first row by position
df.iloc[:5, :2] # first 5 rows, first 2 cols
df.loc[0, 'name'] # cell by label
df.loc[df['age'] >= 30, ['name', 'city']]
# 6) Add / modify columns
df['adult'] = df['age'] >= 18
df['decade'] = df['age'] // 10
df['fullname'] = df['name'] + ' ' + df['city']
df = df.assign(
score = lambda x: x['age'] * 2,
tag = lambda x: np.where(x['adult'], 'A', 'M'),
)
# 7) Rename + drop
df = df.rename(columns={'name': 'first_name'})
df = df.drop(columns=['decade'])
df = df.drop(index=[0, 3])
# 8) Missing data
df.isna().sum() # NA per column
df = df.dropna(subset=['age']) # drop rows missing age
df['age'] = df['age'].fillna(df['age'].median())
df['city'] = df['city'].fillna('Unknown')
# 9) Types
df['age'] = df['age'].astype('Int32') # nullable int
df['city'] = df['city'].astype('category')
df['signup_at'] = pd.to_datetime(df['signup_at'])
# 10) Sort
df = df.sort_values(['city', 'age'], ascending=[True, False])
# 11) Aggregations
df['age'].mean()
df['age'].quantile([0.25, 0.5, 0.75])
df['city'].value_counts()
# 12) Group-by (intro — see groupby lesson for details)
df.groupby('city').agg({'age': 'mean', 'name': 'count'})
# 13) Reshape
wide = df.pivot_table(values='age', index='city', columns='adult', aggfunc='mean')
long = wide.reset_index().melt(id_vars='city')
# 14) Merge / join
other = pd.DataFrame({'city': ['Sydney', 'Brisbane'], 'population': [5_000_000, 2_500_000]})
merged = df.merge(other, on='city', how='left')
# 15) Export
df.to_csv('out.csv', index=False)
df.to_parquet('out.parquet')
df.to_json('out.json', orient='records')
# 16) Performance — vectorise!
df['adult'] = df['age'] >= 18 # vectorised, fast
# vs:
df['adult'] = df.apply(lambda r: r.age >= 18, axis=1) # row-by-row, slow
# For very large data, look at polars / DuckDB.
Why it matters
Vectorised ops on Series / DataFrame are 10-100× faster than .apply per row. If you’re writing .apply(lambda r: ...), look for a column-level expression first — pandas usually has one.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
import pandas as pd
df = pd.DataFrame({
'name': ['Ada', 'Bo', 'Cy'],
'age': [36, 28, 22],
})
print(df)
print(df.dtypes)
Try it Yourself »
Exercise
Load a CSV into a DataFrame.
df = pd.
('users.csv')
Snake case.
Discussion
Loading…