Pandas 字符串处理 str 访问器
承接上一篇《Pandas 缺失值处理》,本篇讲解 Pandas
str访问器,专门用于 Series 文本批量处理,包含判断、截取、替换、分割、正则、清洗、提取,同时标注坑点:str仅支持string / object类型,category分类列需要先转换。保持系列教程统一风格。
前置导入与示例数据
import pandas as pd
import numpy as np
df = pd.DataFrame({
"name": ["张三", "李四", "王五", "赵六", "孙七", " 周八 ", "Tom_99", None],
"phone": ["13800138000", "13900139000", "13700137000", "13600136000", "", "13500135000", "13400134000", pd.NA],
"email": ["zhangsan@abc.com", "lisi@abc.com", "wangwu@xyz.org", "zhaoliu@abc.com", "sunqi@test.cn", "zhouba@abc.com", "tom99@xyz.com", pd.NA],
"address": ["浙江省杭州市西湖区", "上海市浦东新区", "浙江省杭州市余杭区", "北京市朝阳区", "浙江省宁波市鄞州区", "广东省深圳市南山区", "杭州市滨江区", pd.NA]
})
print(df)
一、基础说明
str 访问器是 Pandas 给文本 Series 提供的批量字符串方法,相当于内置字符串函数的向量化版本,不用循环。
⚠️ 重要前提:
- 列类型为
object或者string(推荐新版string类型) Categorical类别列不能直接使用.str,需要先astype("string")- 遇到缺失值
pd.NA / None,默认返回 NA;大部分方法支持na=False参数
# 转为 string 类型(推荐,对空值友好)
df["name"] = df["name"].astype("string")
二、空白处理(清洗高频)
# 去除左右空格
df["name"].str.strip()
# 只去除左侧空格
df["name"].str.lstrip()
# 只去除右侧空格
df["name"].str.rstrip()
# strip 支持自定义字符
df["name"].str.strip("_ ")
三、判断匹配:contains / startswith / endswith
返回布尔 Series,常配合 loc 过滤
# 包含指定文本,na=False 空值返回False,避免报错
df["address"].str.contains("杭州", na=False)
# 以指定字符开头
df["email"].str.startswith("zhang", na=False)
# 以指定字符结尾
df["email"].str.endswith("@abc.com", na=False)
# 正则匹配,开启正则
df["email"].str.contains(r"^zh.*@", regex=True, na=False)
四、大小写转换
df["email"].str.upper() # 全部大写
df["email"].str.lower() # 全部小写
df["email"].str.capitalize() # 首字母大写,其余小写
五、截取字符:slice / []
# 截取前3个字符
df["phone"].str.slice(0, 3)
# 等价写法
df["phone"].str[0:3]
# 从倒数4位开始(手机号后4位)
df["phone"].str[-4:]
六、替换 replace
支持普通文本替换 + 正则替换
# 普通替换
df["address"].str.replace("浙江省", "浙", regex=False)
# 正则替换:把数字全部替换成*
df["name"].str.replace(r"\d", "*", regex=True)
Pandas 2.0+ 默认
regex=False,老版本默认True,建议显式写参数避免歧义。
七、分割 split 拆分字符串
# 按下划线分割,返回列表
df["name"].str.split("_")
# 分割后取第0段
df["name"].str.split("_").str[0]
# 分割并且展开成多列,expand=True
df["email"].str.split("@", expand=True)
八、提取正则 extract(业务神器)
从文本里按正则分组提取内容,非常适合提取手机号、编号、域名
# 提取邮箱用户名和域名
df["email"].str.extract(r"(.+)@(.+)\.(.+)")
- 正则里
()代表分组,每个分组对应输出一列 - 匹配失败返回 NA
九、拼接、计数、长度
# 字符串长度
df["name"].str.len()
# 统计某个字符出现次数
df["email"].str.count(r"@")
# 拼接固定前缀
"prefix_" + df["name"].str.lower()
十、填充、对齐、补齐
# 左对齐,总长度10,不足补空格
df["name"].str.ljust(10)
# 右对齐,总长度10,不足补0(编号补零常用)
df["phone"].str.rjust(11, fillchar="0")
# 居中对齐
df["name"].str.center(10)
# zfill 从左侧补0
df["phone"].str.zfill(11)
十一、字符串布尔判断方法
# 是否全数字
df["phone"].str.isdigit()
# 是否全字母
df["name"].str.isalpha()
# 是否字母+数字
df["name"].str.isalnum()
# 是否空白字符
df["name"].str.isspace()
十二、get 取出列表元素
split 之后得到列表,可以用 .str.get(n) 取出第n个元素,等价 .str[n]
df["email"].str.split("@").str.get(0)
十三、链式清洗示例
res = df["address"].str.strip()\
.str.replace("浙江省", "浙", regex=False)\
.str.replace("上海市", "沪", regex=False)\
.str.contains("杭州", na=False)
十四、常用参数说明
na=False:判断类方法(contains、startswith),NA行返回False,防止报错expand=True:split 拆分后展开为多列DataFrameregex=True:开启正则模式pat:匹配模板repl:替换内容
十五、高频坑清单
- ❌ category 类型直接调用
.str→ 报错,先astype("string") - ❌ 有空值不写
na=False,contains 直接抛出异常 - ❌ replace 忘记
regex=False,特殊字符. * +被当成正则 - ❌ str.len() 对 pd.NA 返回NA,不是0
- ❌ split 之后直接取元素,没有
.str,df["col"].split("_")[0]是错误写法 - ❌ 空字符串
""不是 pd.NA,str.isspace()可以识别空白字符串
十六、综合实战模板
def clean_text_series(s: pd.Series) -> pd.Series:
"""文本清洗流水线:去空格、转string、空文本转为pd.NA"""
s = s.astype("string").str.strip()
s = s.replace(r"^\s*$", pd.NA, regex=True)
return s
# 提取手机号前3位
df["phone_prefix"] = clean_text_series(df["phone"]).str[:3]
# 提取邮箱域名
df["email_domain"] = clean_text_series(df["email"]).str.extract(r"@(.+)$")[0]
print(df[["phone","phone_prefix","email","email_domain"]])
十七、API速查表
| API | 作用 |
|---|---|
| str.strip() | 去除两端空白 |
| str.contains() | 包含匹配,支持正则 |
| str.startswith / endswith | 前缀、后缀匹配 |
| str.slice / str[] | 字符截取 |
| str.replace() | 文本替换 |
| str.split(expand=True) | 分割展开多列 |
| str.extract() | 正则分组提取 |
| str.len() | 获取字符串长度 |
| str.isdigit / isalpha | 字符类型判断 |
| str.lower / upper | 大小写转换 |
| str.zfill / rjust | 补零对齐 |
0 条笔记