文本数据:.str 访问器
本教程共 54 篇 · 第 48 篇 · 更新于 2026-08-11 · 约 8 分钟阅读
本节目标:学会用 .str 访问器对一整列文本做大小写转换、拆分、替换、连接和判断,掌握 pandas 3.0 的字符串类型。
.str 访问器:给整列批量处理字符串
Python 字符串有 "hello".upper()、"a,b,c".split(",") 这些方法,但只作用于单个字符串。数据清洗时,你要处理的是整列几百个字符串。用循环一个个来?太慢也太啰嗦。
pandas 的解法是 .str 访问器:Series.str.方法名(),对列里每个元素批量执行同样的字符串操作,方法名和 Python 字符串方法基本一一对应。
import pandas as pd
s = pd.Series(["hello", "World", "pandas", "Python"])
print(s.dtype)
# str
print(s.str.upper())
# 0 HELLO
# 1 WORLD
# 2 PANDAS
# 3 PYTHON
# dtype: str
Notepandas 3.0 起,纯字符串列默认的类型就是
str(StringDtype 的别名),不再是以前的 object。这对日常使用基本无感,但意味着字符串列有了专属类型,行为更可控。
大小写转换
一套方法把大小写玩出花:
import pandas as pd
s = pd.Series(["Hello World", "PYTHON pandas", "data SCIENCE"])
print(s.str.lower()) # 全部小写
print(s.str.upper()) # 全部大写
print(s.str.capitalize()) # 首字母大写,其余小写
print(s.str.title()) # 每个单词首字母大写
print(s.str.swapcase()) # 大小写互换
去空格
用户输入的数据,前后常带着空格,肉眼看不见,一比较就出问题。strip 系列就是干这个的:
import pandas as pd
s = pd.Series([" hello ", "world ", " pandas", " python "])
print(s.str.strip()) # 去掉首尾空格
print(s.str.lstrip()) # 只去左边
print(s.str.rstrip()) # 只去右边
# 0 hello
# 1 world
# 2 pandas
# 3 python
# dtype: str
清洗列名也是常见场景。DataFrame 的列名是 Index,同样有 .str:
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randn(2, 2), columns=[" 姓名 ", " 年龄 "])
df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_")
print(df.columns.tolist())
# ['姓名', '年龄']
长度与计数
len 统计每个字符串的长度,count 统计某个字符或模式出现的次数:
import pandas as pd
s = pd.Series(["hello", "world", "python", "pandas"])
print(s.str.len())
# 0 5
# 1 5
# 2 6
# 3 6
# dtype: int64
print(s.str.count("o"))
# 0 1
# 1 1
# 2 1
# 3 0
判断类方法
判断类方法返回布尔 Series,直接可以当布尔索引(§20)用:
import pandas as pd
s = pd.Series(["123", "abc", "1a2", " "])
print(s.str.isdigit()) # 是否全是数字
# 0 True
# 1 False
# 2 False
# 3 False
print(s.str.isalpha()) # 是否全是字母
print(s.str.isalnum()) # 是否全是字母或数字
还有 startswith、endswith、contains 三兄弟,判断”以什么开头/结尾/包含什么”:
import pandas as pd
s = pd.Series(["hello world", "python pandas", "data science"])
print(s.str.startswith("hello"))
# 0 True
# 1 False
# 2 False
print(s.str.endswith("pandas"))
# 0 False
# 1 True
# 2 False
print(s.str.contains("data"))
# 0 False
# 1 False
# 2 True
contains 默认大小写敏感,想忽略大小写加 case=False。contains 还支持正则表达式,比如 s.str.contains(r"\d+") 找出带数字的行——正则的完整玩法下节展开。
拆分:split
split 按分隔符把每个字符串拆成列表:
import pandas as pd
s = pd.Series(["a_b_c", "c_d_e", "f_g_h"])
print(s.str.split("_"))
# 0 [a, b, c]
# 1 [c, d, e]
# 2 [f, g, h]
# dtype: object
# 拆完取第 2 段
print(s.str.split("_").str[1])
# 0 b
# 1 d
# 2 g
拆出来的列表不直观?expand=True 直接把每一段变成一列,得到 DataFrame:
import pandas as pd
s = pd.Series(["a_b_c", "c_d_e", "f_g_h"])
print(s.str.split("_", expand=True))
# 0 1 2
# 0 a b c
# 1 c d e
# 2 f g h
# n=1 只拆第一刀,剩下的留在最后一段
print(s.str.split("_", expand=True, n=1))
# 0 1
# 0 a b_c
# 1 c d_e
# 2 f g_h
rsplit 从右边开始拆。日期字符串拆成年月日,是 expand 最常见的用途。
替换:replace
替换有两种模式,由 regex 参数控制:
import pandas as pd
s = pd.Series(["hello world", "python pandas"])
# 字面替换:把 o 换成 0(regex=False 表示按普通字符串处理)
print(s.str.replace("o", "0", regex=False))
# 0 hell0 w0rld
# 1 pyth0n pandas
# 默认 regex=True:模式按正则解释
print(s.str.replace("l+", "L", regex=True))
# 0 heLo worLd
# 1 python pandas
Warning
str.replace默认regex=True,连单字符也会按正则处理。想替换的字面量里带.、$、\这些正则特殊字符时,要么写regex=False,要么把特殊字符转义。用regex=False最省心。
removeprefix 和 removesuffix 专门去掉固定前缀/后缀,比如文件名批量去后缀:s.str.removesuffix(".csv")。
连接:cat
两个方向:整列拼成一个字符串,或者逐行拼接两列。
import pandas as pd
s = pd.Series(["a", "b", "c", "d"])
# 整列拼成一个字符串,用逗号分隔
print(s.str.cat(sep=","))
# a,b,c,d
# 两列逐行拼接
s2 = pd.Series(["1", "2", "3", "4"])
print(s.str.cat(s2, sep="-"))
# 0 a-1
# 1 b-2
# 2 c-3
# 3 d-4
# dtype: str
更常见的逐行拼接其实用 + 就行:s + "-" + s2,效果一样。cat 的优势是能处理缺失值:默认跳过 NaN,也可以用 na_rep 指定缺失值的替代文本。
按位置取字符与切片
[] 可以直接按位置取每个字符串的字符,超出长度返回 NaN,不会报错:
import pandas as pd
s = pd.Series(["hello", "world", "python", "pandas"])
print(s.str[0]) # 每个字符串的第一个字符
# 0 h
# 1 w
# 2 p
# 3 p
df = pd.DataFrame({"编号": ["A-001", "B-002", "C-003"]})
print(df["编号"].str[2:]) # 去掉前两个字符
# 0 001
# 1 002
# 2 003
# dtype: str
切片规则和 Python 字符串完全一致,str[2:] 取从第 3 个字符到结尾。
缺失值怎么处理
.str 的方法对缺失值很友好:大多数方法自动跳过 NaN,输出还是 NaN;判断类方法(startswith、contains 等)可以传 na 参数指定缺失值算 True 还是 False:
import pandas as pd
import numpy as np
s = pd.Series(["apple", np.nan, "banana"])
print(s.str.upper())
# 0 APPLE
# 1 NaN
# 2 BANANA
# 缺失值在判断里算 False,避免筛选时报错
print(s.str.contains("a", na=False))
# 0 True
# 1 False
# 2 True
# dtype: bool
3.0 的字符串类型
pandas 3.0 的字符串列默认推断为 dtype="str",这是新的 StringDtype,缺失值用 NaN 表示。如果你更习惯 pandas 2.x 时代 pd.NA 的缺失语义,可以显式指定 dtype="string":
import pandas as pd
print(pd.Series(["a", "b", None]).dtype)
# str
print(pd.Series(["a", "b", None], dtype="string").dtype)
# string
两个都是 StringDtype,只是缺失值表示不同(NaN vs pd.NA)。旧代码里常见的 object 类型字符串列,.str 方法照样能用;想升级成新类型,astype("str") 即可。装了 PyArrow 时,str 类型自动用 PyArrow 存储,内存更省、部分操作更快。
Tip文本清洗的固定套路:
strip去空格 →lower统一大小写 →replace规范格式 →contains/isdigit校验数据。把这四步串起来,绝大多数脏文本都能收拾干净。
小结
.str 访问器让字符串操作从”逐条处理”变成”整列处理”:大小写、去空格、拆分、替换、连接、判断一应俱全,方法名和 Python 字符串方法对齐,上手成本极低。配合 3.0 的 str 字符串类型,文本数据在 pandas 里终于有了正经类型。下一节在此基础上进阶:正则表达式和 extract 提取。