.str accessor
pandas string accessor `.str` exposes vectorised text operations on a Series of strings — split, contains, extract, replace, slice, lower, strip, and dozens more. They handle missing values gracefully and run in C-speed loops, which is dramatically faster than Series.apply(lambda x: x.foo()).
Vectorised string ops for cleaning and feature work
EXAMPLE
import pandas as pd
import numpy as np
df = pd.DataFrame({
'email': ['Alice@Example.com', ' bob@example.com ', None, 'CAROL@example.com'],
'name': ['Alice Smith', 'Bob Jones', 'Carol Lee', 'Daniel O\'Connor'],
'address': ['12 Oak St, Sydney NSW 2000',
'34 Pine Rd, Melbourne VIC 3000',
None,
'78 Birch Ln, Brisbane QLD 4000'],
})
# 1) Normalise emails: trim, lowercase
df['email_norm'] = df['email'].str.strip().str.lower()
# 2) Filter rows whose email looks valid
mask = df['email_norm'].str.contains(r'^[^@]+@[^@]+\.[^@]+$', na=False, regex=True)
print(df.loc[mask, ['email_norm']])
# 3) Split a name into first/last
df[['first', 'last']] = df['name'].str.split(' ', n=1, expand=True)
# 4) Extract structured fields with named groups
addr_re = r'(?P<street>[^,]+),\s*(?P<city>[A-Za-z ]+)\s+(?P<state>[A-Z]{2,3})\s+(?P<postcode>\d{4})'
df = df.join(df['address'].str.extract(addr_re))
print(df[['street','city','state','postcode']])
# 5) Multiple replacements at once via a regex dict
title_fix = {
r'^Mr ': 'Mr. ',
r'^Mrs ': 'Mrs. ',
r'^Dr ': 'Dr. ',
}
df['name'] = df['name'].replace(title_fix, regex=True)
# 6) Slice characters by position (e.g. first 3 chars as a code)
df['email_user'] = df['email_norm'].str.split('@').str[0]
# 7) Length, startswith, endswith — all vectorised, all NA-aware
df['email_len'] = df['email_norm'].str.len()
df['gov_email'] = df['email_norm'].str.endswith('.gov.au', na=False)
# 8) Concatenate Series with separators
full = df['first'].str.cat(df['last'], sep=' ', na_rep='?')
# 9) Performance tip: ensure the column is a real string dtype (not object)
df['email_norm'] = df['email_norm'].astype('string') # nullable string dtype
# String dtype enables the same str. operations but with better NA handling.
Why it matters
Reach for the `string` (StringDtype) dtype over the legacy object dtype on text columns. It preserves missing values as `pd.NA` consistently across operations, which spares you a stream of \"object inference\" surprises when you concatenate, groupby, or write to parquet.
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['domain'] = df['email'].str.split('@').str[1]
df['is_corp'] = df['email'].str.contains(r'\.com\$', regex=True)
df['name'] = df['name'].str.strip().str.title()
Try it Yourself »
Discussion
Loading…