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 | 索引切片 |
到此这篇关于python中pandas进行字符串操作的完整教学的文章就介绍到这了,更多相关python pandas字符串操作内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论