本节聚焦字符串的检索、条件判断与替换方法,常与布尔索引结合完成数据筛选和清洗。
1. 包含判断:str.contains()
检查每个字符串是否包含指定模式,返回布尔 Series。
基本用法
s = pd.Series(['apple pie', 'banana bread', 'cherry cake', None])
s.str.contains('an')
# 0 False
# 1 True
# 2 False
# 3 NaN参数
| 参数 | 说明 |
|---|---|
pat | 要匹配的模式(字符串或正则) |
case | 是否区分大小写(默认 True) |
flags | 正则标志位(如 re.IGNORECASE) |
na | 缺失值填充值:默认 NaN,可设为 False / True |
regex | 是否将 pat 当正则表达式(默认 True) |
正则与大小写
# 忽略大小写
s.str.contains('APPLE', case=False)
# 正则模式:以 a 开头或包含数字
s.str.contains('^a|\d', regex=True)
# 字面模式:不解释为正则
s.str.contains('a.c', regex=False)
# 缺失值处理为 False
s.str.contains('an', na=False)
# 使用正则标志位
import re
s.str.contains('apple', flags=re.IGNORECASE)与布尔索引结合
df = pd.DataFrame({'商品': ['iPhone 15', 'iPad Air', 'MacBook'], '价格': [5999, 3499, 8999]})
# 筛选包含 'iPhone' 或 'Mac' 的商品
df[df['商品'].str.contains('iPhone|Mac', na=False)]
# 筛选以 'i' 开头的商品
df[df['商品'].str.startswith('i')]注意
在 pandas 2.x 中,
regex参数必须显式指定,不再自动推断。
2. 前缀与后缀判断
str.startswith()
s = pd.Series(['apple', 'banana', 'avocado'])
s.str.startswith('a')
# 0 True
# 1 False
# 2 Truestr.endswith()
s.str.endswith('e')
# 0 True
# 1 False
# 2 False组合筛选
# 筛选邮箱为 .com 或 .org 结尾
df['邮箱'].str.endswith(('.com', '.org'), na=False)| 方法 | 说明 |
|---|---|
na | 缺失值处理(默认 NaN) |
3. 全匹配判断:str.match() / str.fullmatch()
str.match()
检查字符串开头是否匹配正则模式。
s = pd.Series(['abc123', 'xyz789', 'abc456'])
s.str.match('abc')
# 0 True
# 1 False
# 2 Truestr.fullmatch()
要求整个字符串完全匹配正则模式(pandas 2.x 新增)。
s.str.fullmatch(r'\d+')
# 0 False
# 1 False
# 2 False(全数字才为 True)match vs contains
str.match:从头匹配(等价于re.match)str.contains:包含即可(等价于re.search)str.fullmatch:完全匹配
4. 替换:str.replace()
字面替换
s = pd.Series(['apple orange', 'banana apple', 'cherry'])
s.str.replace('apple', 'pineapple', regex=False)
# 0 pineapple orange
# 1 banana pineapple
# 2 cherry正则替换
# 将所有数字替换为 #
s = pd.Series(['订单 A1001', '订单 B2002'])
s.str.replace(r'\d', '#', regex=True)
# 0 订单 A####
# 1 订单 B####
# 删除所有非字母数字字符
s.str.replace(r'[^a-zA-Z0-9]', '', regex=True)使用捕获组
s = pd.Series(['2024-01-15', '2025-06-30'])
# 将日期格式从 YYYY-MM-DD 转换为 DD/MM/YYYY
s.str.replace(r'(\d{4})-(\d{2})-(\d{2})', r'\3/\2/\1', regex=True)
# 0 15/01/2024
# 1 30/06/2025参数
| 参数 | 说明 |
|---|---|
pat | 查找的模式(字符串或正则) |
repl | 替换内容,可包含捕获组 \1 |
case | 是否区分大小写 |
flags | 正则标志 |
regex | 是否为正则(pandas 2.x 必须显式) |
n | 最大替换次数(-1 表示全部替换) |
# 仅替换第一个匹配
s.str.replace('a', 'X', n=1, regex=False)注意
str.replace的case参数只对regex=True(默认)生效- 替换为函数(高级用法):
repl可传入可调用对象,对每个匹配执行函数
import re
s.str.replace(r'\d+', lambda m: str(int(m.group()) * 2), regex=True)5. 删除前缀/后缀:str.removeprefix() / str.removesuffix()
pandas 2.x 新增,基于 Python 3.9 的字符串方法。
s = pd.Series(['pre_apple', 'pre_banana'])
s.str.removeprefix('pre_')
# 0 apple
# 1 banana
s2 = pd.Series(['file.csv', 'data.csv'])
s2.str.removesuffix('.csv')
# 0 file
# 1 data与 replace 的区别
removeprefix只去除开头的完全匹配removesuffix只去除末尾的完全匹配- 更安全、语义更清晰
6. 综合筛选示例
df = pd.DataFrame({
'姓名': ['张三', '李四', '王五'],
'电话': ['138-0000-0000', '400-800-8888', '010-12345678'],
'邮箱': ['zhang@test.com', 'li@test.org', None]
})
# 筛选手机号(1 开头,11 位数字的变形)
df[df['电话'].str.startswith('138', na=False)]
# 筛选企业邮箱(非个人邮箱域名)
df[df['邮箱'].str.endswith('.com', na=False)]
# 筛选中包含数字的姓名
df[df['姓名'].str.contains(r'\d', regex=True, na=False)]
# 统一替换为规范格式
df['电话_清理'] = df['电话'].str.replace(r'[^0-9]', '', regex=True)小结
- 判断:
contains、startswith、endswith、match、fullmatch- 替换:
replace(字面/正则/捕获组/函数)- 删除:
removeprefix、removesuffix- 与布尔索引结合完成筛选:
df[df['col'].str.contains(...)]