Data Analysis with pandas · Analysis with pandas
Fast and Correct pandas 3 Code
Write pandas code that is correct under copy-on-write, uses the new string dtype, saves memory with categories, and avoids slow patterns.
What you'll build
A before-and-after of common pandas habits: the copy-on-write behaviour that changed in pandas 3, the dedicated str dtype, memory savings with category, and a vectorised replacement for a slow apply.
The idea
- Copy-on-write (default in pandas 3): every selection behaves like a copy; modifying a subset never changes the original, and chained assignment never works. Always modify with one
loccall on the DataFrame you mean. - String dtype: text columns use the
strdtype by default in pandas 3 instead of genericobject. - Categoricals store repeated labels once: large memory savings for columns like country or status.
- Vectorise: column arithmetic,
.strand.dtaccessors,np.selectbeatapply(axis=1).
The code
import numpy as np
import pandas as pd
df = pd.DataFrame({"country": ["DE", "US", "DE"] * 1000, "amount": np.arange(3000, dtype=float)})
subset = df[df["country"] == "DE"]
subset.loc[:, "amount"] = 0 # modifies only subset (copy-on-write)
print("original untouched:", df["amount"].sum() > 0)
df.loc[df["country"] == "DE", "amount"] = 0 # the right way to change df
print("DE rows now zero:", (df.loc[df["country"] == "DE", "amount"] == 0).all())
print("text dtype:", df["country"].dtype)
as_category = df["country"].astype("category")
print("memory bytes:", df["country"].memory_usage(deep=True), "->", as_category.memory_usage(deep=True))
df["band"] = np.select([df["amount"] == 0, df["amount"] < 1000], ["zero", "low"], default="high")
print(df["band"].value_counts().to_dict())
Output
original untouched: True
DE rows now zero: True
text dtype: str
memory bytes: 81072 -> 3126
{'zero': 2000, 'high': 667, 'low': 333}Common mistakes
- Relying on modifying a filtered DataFrame to change the original (worked by accident in some old cases, never in pandas 3).
objectcolumns full of strings in old code; convert withastype("str")(or let pandas 3 infer it).apply(lambda row: ..., axis=1)for logic thatnp.select,np.whereor.strmethods can express.- Loading everything as
float64/objectwhencategoryor smaller numeric types would do.
Key points
- In pandas 3, selections behave like copies: assign with loc on the original.
- Text uses the str dtype; repeated labels belong in categories.
- Vectorised operations are faster and clearer than row-wise apply.
Further reading: Copy-on-Write · What's new in pandas 3.0 · Scaling to large datasets
Practice questions
What does copy-on-write mean for code that modifies a filtered DataFrame?
Answer
The filtered result behaves as a copy; changing it never changes the original, so modify the original with a single loc assignment.
Why convert repeated text labels to category?
Answer
Categories store each distinct value once and use small integer codes per row, saving memory and speeding up grouping.
What can replace row-wise apply for conditional columns?
Answer
Vectorised tools: np.where for two outcomes, np.select for several, pd.cut for ranges, and .str/.dt accessors.
Open in the app to mark lessons complete, take notes and track your progress.