Object/string columns grow a .str accessor: vectorized Python-string operations that return a Series. They skip (or NA) missing values.
Goal
Trim, case-fold, test, extract, split, and replace text without a Python for loop.
Strip and case
names = pd.Series(
[" ada kwon", "ALAN TURING", "Grace Hopper", "linus", " nia "],
name="name",
)
clean = names.str.strip().str.title()
print(names)
print()
print(clean)Common chain: strip → lower or title → then match.
Contains, starts, ends
names = pd.Series(
[" ada kwon", "ALAN TURING", "Grace Hopper", "linus", " nia "],
name="name",
)
clean = names.str.strip()
print(clean.str.contains("a", case=False, na=False))
print()
print(clean[clean.str.lower().str.startswith("a")])na=False makes missing values False so they do not leak into a filter as NA.
Replace and length
clean = pd.Series(["Ada Kwon", "Alan Turing", "Grace Hopper"], name="name")
print(clean.str.replace(" ", "_", regex=False))
print()
print(clean.str.len())Use regex=True only when you mean it. For a literal dot, regex=False is safer.
Split into columns
clean = pd.Series(["Ada Kwon", "Alan Turing", "Grace Hopper", "Linus"], name="name")
parts = clean.str.split(n=1, expand=True)
parts.columns = ["first", "last"]
print(parts)expand=True returns a DataFrame. Without it you get a Series of lists.
Extract with a regex
codes = pd.Series(["A-12", "B-7", "C-31", "bad"], name="sku")
print(codes.str.extract(r"([A-Z])-(\d+)"))Unmatched rows are NA.
Slice
clean = pd.Series(["Ada Kwon", "Alan Turing", "Grace Hopper"], name="name")
print(clean.str[:4])
print(clean.str[-3:])You should see
messy.csv in the Files chapter needs .str.strip() and .str.title() before you can drop duplicate people.