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 只能用于 objectstring 类型的列。数值列需先 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-总览|← 返回总览]]

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐