Python-pandas-文本处理
·
Pandas 文本处理
Pandas 通过 .str 访问器提供向量化字符串操作,避免逐行循环,性能远超 Python 原生字符串方法。
🔤 .str 访问器基础
import pandas as pd
import numpy as np
s = pd.Series(['张三', '李四', '王五', '赵六', np.nan])
# 所有 str 方法自动跳过 NaN
print(s.str.len()) # [2, 2, 2, 2, NaN]
print(s.str.lower()) # 全部小写
print(s.str.upper()) # 全部大写
# 也适用于 DataFrame 的列
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie'],
'email': ['alice@qq.com', 'bob@gmail.com', 'charlie@163.com']
})
print(df['email'].str.contains('gmail'))
print(df['name'].str.lower())
重要说明: .str 只能用于 object 或 string 类型的列。数值列需先 astype(str) 转换。
✂️ 切片与索引
s = pd.Series(['abcdef', 'ghijkl', 'mnopqr'])
# 位置切片(与 Python 字符串一致)
print(s.str[0]) # 第一个字符
print(s.str[:3]) # 前三个字符
print(s.str[3:5]) # 第 4-5 个字符
print(s.str[-3:]) # 最后三个字符
# get(): 按位置取值(越界不报错)
print(s.str.get(0)) # 第 0 个字符
print(s.str.get(10)) # 越界返回 NaN(而非报错!)
🔍 查找与判断
s = pd.Series(['hello world', 'foo bar', 'baz qux corge'])
# contains: 是否包含
print(s.str.contains('oo')) # 是否含 'oo'
print(s.str.contains('WORLD', case=False)) # 忽略大小写
print(s.str.contains(r'\bw\w+')) # 正则: 以 w 开头的单词
print(s.str.contains('foo|baz')) # 正则: 含 foo 或 baz
# startswith / endswith
print(s.str.startswith('he'))
print(s.str.endswith('ld'))
# find / rfind: 返回位置(不存在返回 -1)
print(s.str.find('o')) # 第一个 'o' 的位置
print(s.str.rfind('o')) # 最后一个 'o' 的位置
# match: 从开头匹配正则
print(s.str.match(r'h\w+')) # 以 h 开头的单词
# fullmatch: 整个字符串匹配
print(s.str.fullmatch(r'\w+ \w+')) # 恰好两个单词
# count: 子串出现次数
print(s.str.count('o'))
# len: 字符串长度
print(s.str.len())
🔧 提取与替换
extract() — 正则提取 ⭐
df = pd.DataFrame({
'email': ['alice@qq.com', 'bob@gmail.com', 'charlie@163.com']
})
# 提取分组
df[['user', 'domain']] = df['email'].str.extract(
r'([a-zA-Z0-9._]+)@([a-zA-Z0-9.]+)'
)
print(df)
# email user domain
# 0 alice@qq.com alice qq.com
# 1 bob@gmail.com bob gmail.com
# 2 charlie@163.com charlie 163.com
extractall() — 提取所有匹配
s = pd.Series(['a1b2', 'c3', 'd4e5f6'])
matches = s.str.extractall(r'([a-z])(\d)')
# 返回 MultiIndex: (原始行号, 匹配号)
# match
# 0 0 a 1
# 1 b 2
# 1 0 c 3
# 2 0 d 4
# 1 e 5
# 2 f 6
# 展开
wide = s.str.extractall(r'([a-z])(\d)').unstack()
replace() — 字符串替换
s = pd.Series(['foo_bar', 'bar_baz', 'baz_qux'])
# 普通替换
print(s.str.replace('_', '-'))
# 正则替换
print(s.str.replace(r'^(...)', r'[\1]', regex=True))
# [foo]_bar [bar]_baz [baz]_qux
# n: 只替换前 n 次
print(s.str.replace('_', '-', n=1))
🧩 拆分与拼接
split() — 拆分
s = pd.Series(['a,b,c', 'd,e', 'f,g,h,i'])
# 拆分为列表(返回 Series of lists)
print(s.str.split(','))
# 0 [a, b, c]
# 1 [d, e]
# 2 [f, g, h, i]
# expand=True: 拆分为 DataFrame
df_split = s.str.split(',', expand=True)
# 0 1 2 3
# 0 a b c None
# 1 d e None None
# 2 f g h i
# n: 限制拆分次数
print(s.str.split(',', n=1, expand=True))
# 0 1
# 0 a b,c
# 1 d e
# 2 f g,h,i
# rsplit: 从右向左拆分
print(s.str.rsplit(',', n=1, expand=True))
cat() — 拼接
s1 = pd.Series(['a', 'b', 'c'])
s2 = pd.Series(['x', 'y', 'z'])
# 拼接两个 Series
print(s1.str.cat(s2, sep='-')) # ['a-x', 'b-y', 'c-z']
# 拼接一个 Series 的元素为单个字符串
print(s1.str.cat(sep=', ')) # 'a, b, c'
# 拼接 DataFrame 的多列
df = pd.DataFrame({'first': ['A', 'B'], 'last': ['Smith', 'Jones']})
df['full'] = df['first'].str.cat(df['last'], sep=' ')
join() — 用分隔符连接列表元素
s = pd.Series([['a', 'b', 'c'], ['d', 'e'], ['f']])
print(s.str.join('-')) # ['a-b-c', 'd-e', 'f']
🧹 清理与修整
s = pd.Series([' hello ', ' world', 'foo '])
# 去空格
print(s.str.strip()) # 去两端空格
print(s.str.lstrip()) # 去左侧空格
print(s.str.rstrip()) # 去右侧空格
# 指定要去除的字符
print(s.str.strip('[]')) # 去两端的中括号
# pad / center / ljust / rjust
s = pd.Series(['a', 'bb', 'ccc'])
print(s.str.pad(5, side='both', fillchar='-')) # 居中填充
print(s.str.pad(5, side='left', fillchar='0')) # 左填充
print(s.str.pad(5, side='right', fillchar='.')) # 右填充
# 等价: s.str.center(5, '-'), s.str.ljust(5, '0'), s.str.rjust(5, '.')
# zfill: 左侧补零
s = pd.Series(['12', '345', '6'])
print(s.str.zfill(4)) # ['0012', '0345', '0006']
# repeat: 重复字符串
print(s.str.repeat(2)) # ['1212', '345345', '66']
# wrap: 文本换行
long_text = pd.Series(['This is a very long sentence that needs wrapping'])
print(long_text.str.wrap(20)) # 每 20 字符换行
🔠 大小写转换
s = pd.Series(['hello world', 'foo BAR', 'Baz QUX'])
print(s.str.lower()) # 全小写
print(s.str.upper()) # 全大写
print(s.str.title()) # 每个单词首字母大写
print(s.str.capitalize()) # 句首大写
print(s.str.swapcase()) # 大小写互换
print(s.str.casefold()) # 更激进的小写化(用于不区分大小写比较)
🔢 数值提取与判断
# 判断类
s = pd.Series(['123', 'abc', '456def', ' '])
print(s.str.isnumeric()) # 是否全数字
print(s.str.isalpha()) # 是否全字母
print(s.str.isalnum()) # 是否全字母数字
print(s.str.isdigit()) # 是否全数字字符
print(s.str.isdecimal()) # 是否全十进制数字
print(s.str.isspace()) # 是否全空白
print(s.str.islower()) # 是否全小写
print(s.str.isupper()) # 是否全大写
print(s.str.istitle()) # 是否标题格式
# 正则 + 数值转换
s = pd.Series(['价格: 100元', '价格: 250元', '价格: 38元'])
prices = s.str.extract(r'(\d+)').astype(float)
🎯 高级技巧
get_dummies() — 字符串独热编码
s = pd.Series(['a|b', 'a', 'b|c|d'])
dummies = s.str.get_dummies(sep='|')
# a b c d
# 0 1 1 0 0
# 1 1 0 0 0
# 2 0 1 1 1
normalize() — Unicode 规范化
s = pd.Series(['café', 'café']) # 视觉相同但编码不同
print(s.str.normalize('NFC')) # 组合形式
print(s.str.normalize('NFD')) # 分解形式
removeprefix() / removesuffix()
s = pd.Series(['prefix_foo', 'prefix_bar'])
print(s.str.removeprefix('prefix_')) # ['_foo', '_bar']
print(s.str.removesuffix('.txt'))
链式 str 操作
emails = pd.Series([' ALICE@QQ.COM ', 'BOB@GMAIL.COM'])
# 清洗 -> 提取 -> 转换
result = (emails
.str.strip()
.str.lower()
.str.extract(r'(.+)@(.+)'))
📝 .str 方法速查表
| 类别 | 方法 | 说明 |
|---|---|---|
| 判断 | contains, startswith, endswith, match |
匹配检查 |
| 判断 | isnumeric, isalpha, isalnum, isdigit |
类型检查 |
| 查找 | find, rfind, count |
位置与计数 |
| 提取 | extract, extractall |
正则提取 |
| 替换 | replace |
字符串替换 |
| 拆分 | split, rsplit, partition |
拆分 |
| 拼接 | cat, join |
合并 |
| 清理 | strip, lstrip, rstrip |
去空格 |
| 填充 | pad, center, ljust, rjust, zfill |
对齐填充 |
| 大小写 | lower, upper, title, capitalize |
大小写 |
| 编码 | get_dummies, normalize |
转换 |
| 切片 | [], get, slice |
索引切片 |
[[pandas2-总览|← 返回总览]]
更多推荐



所有评论(0)