核心概念:.str 访问器
在 Pandas 中,当你需要对一列字符串进行操作时,不能直接使用 Python 内置的字符串方法(如 .upper()、.split() 等),你必须使用 Pandas 提供的 .str 访问器。

.str 访问器将 Pandas 的 Series 对象包装起来,并提供了大量与字符串相关的方法,这些方法的行为与 Python 内置方法类似,但它们能够:
- 自动处理缺失值 (
NaN):不会因为NaN而报错。 - 高效地向量化操作:在底层用 C 语言优化,比在循环中逐个处理字符串快得多。
基本语法:
import pandas as pd
import numpy as np
# 创建一个示例 DataFrame
data = {'name': ['Alice', 'Bob', 'Charlie', 'David', np.nan, 'Eve'],
'city': ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix', 'Philadelphia']}
df = pd.DataFrame(data)
# 对 'name' 列进行操作
df['name_upper'] = df['name'].str.upper()
print(df)
输出:
name city name_upper
0 Alice New York ALICE
1 Bob Los Angeles BOB
2 Charlie Chicago CHARLIE
3 David Houston DAVID
4 NaN Phoenix NaN
5 Eve Philadelphia EVE
注意,NaN 保持了原样,没有被报错。
常用 .str 方法详解
下面我们分类介绍最常用的一些 .str 方法。
1 基本修改方法
这些方法用于改变字符串的大小写或填充。
| 方法 | 描述 | 示例 |
|---|---|---|
.str.lower() |
转换为小写 | df['name'].str.lower() |
.str.upper() |
转换为大写 | df['name'].str.upper() |
.str.title() |
格式 (每个单词首字母大写) | df['city'].str.title() |
.str.capitalize() |
转换为字符串首字母大写 | df['name'].str.capitalize() |
.str.strip() |
去除字符串两端的空白字符(空格、换行等) | df['name'].str.strip() |
.str.lstrip() |
去除字符串左端的空白字符 | df['name'].str.lstrip() |
.str.rstrip() |
去除字符串右端的空白字符 | df['name'].str.rstrip() |
示例:
df['city_clean'] = df['city'].str.strip().str.title() print(df[['city', 'city_clean']])
2 拆分与连接
| 方法 | 描述 | 示例 |
|---|---|---|
.str.split() |
拆分字符串,默认按空格拆分,返回一个列表 | df['city'].str.split() |
.str.split(pat=...) |
按指定分隔符 pat 拆分 |
df['city'].str.split(pat=' ') |
.str.get() |
从拆分后的列表中获取指定索引的元素 | df['city'].str.split().str.get(0) 获取城市名 |
.str.cat() |
连接字符串,可以指定分隔符 sep |
df['name'].str.cat(df['city'], sep=' from ') |
示例:
# 拆分城市名和州(假设数据中有州)
df['full_location'] = ['New York, NY', 'Los Angeles, CA', 'Chicago, IL', 'Houston, TX', 'Phoenix, AZ', 'Philadelphia, PA']
df['state'] = df['full_location'].str.split(', ').str.get(1)
df['city_only'] = df['full_location'].str.split(', ').str.get(0)
print(df[['full_location', 'city_only', 'state']])
3 替换与模式匹配
这是文本处理的核心,支持正则表达式。
| 方法 | 描述 | 示例 |
|---|---|---|
.str.replace() |
替换字符串中的匹配项 | df['name'].str.replace('a', '@') |
.str.contains() |
检查字符串是否包含某个子串,返回布尔值 | df['city'].str.contains('New') |
.str.startswith() |
检查字符串是否以指定子串开头 | df['city'].str.startswith('New') |
.str.endswith() |
检查字符串是否以指定子串结尾 | df['city'].str.endswith('on') |
.str.match() |
检查字符串是否从头开始匹配正则表达式 | df['city'].str.match('New.*') |
.str.fullmatch() |
检查字符串是否完全匹配正则表达式 | df['city'].str.fullmatch('New York') |
.str.extract() |
从字符串中提取匹配正则表达式的第一个分组 | df['full_location'].str.extract(r'(\w+), (\w+)') |
.str.extractall() |
提取所有匹配的分组 | (较少用,通常用于多级索引) |
.str.findall() |
找到所有匹配正则表达式的子串,返回列表 | df['full_location'].str.findall(r'\w+') |
正则表达式 (re) 元字符备忘录:
- : 任意字符
- : 0次或多次
- : 1次或多次
- : 0次或1次
^: 字符串开头- : 字符串结尾
[]: 字符集,如[a-z]表示任意小写字母- : 分组,用于提取
\d: 数字\w: 单词字符 (字母, 数字, 下划线)\s: 空白字符
示例:
# 1. 替换
df['name_with_underscores'] = df['name'].str.replace('a', '_a_')
# 2. 检查包含
df['has_i'] = df['name'].str.contains('i') # 'i' 或 'I'
# 3. 提取州代码 (使用 extract)
# r'' 表示原始字符串,避免反斜杠转义
states = df['full_location'].str.extract(r', (\w{2})')
states.columns = ['state_code'] # 为提取的列命名
df = pd.concat([df, states], axis=1)
# 4. 使用正则表达式替换 (移除所有非字母字符)
df['name_cleaned'] = df['name'].str.replace('[^a-zA-Z]', '', regex=True)
print(df[['name', 'name_with_underscores', 'has_i', 'full_location', 'state_code', 'name_cleaned']])
4 长度与计数
| 方法 | 描述 | 示例 |
|---|---|---|
.str.len() |
计算字符串的长度 | df['name'].str.len() |
.str.count() |
计算子串在字符串中出现的次数 | df['name'].str.count('a') |
示例:
df['name_length'] = df['name'].str.len()
df['a_count'] = df['name'].str.count('a')
print(df[['name', 'name_length', 'a_count']])
实战案例:数据清洗
假设我们有一份包含用户评论的“脏”数据,需要进行清洗。
原始数据:
import pandas as pd
import numpy as np
data = {
'id': [1, 2, 3, 4, 5],
'review': [
'This product is AMAZING!!!',
'it is okay, not great.',
'Worst purchase EVER. DO NOT BUY.',
'Good value for money.',
np.nan
]
}
reviews_df = pd.DataFrame(data)
清洗目标:
- 将所有文本转换为小写,以便进行统一分析。
- 去除标点符号(, 等)。
- 将
NaN值替换为字符串'no review'。
解决方案:
# 1. 转换为小写
reviews_df['review_clean'] = reviews_df['review'].str.lower()
# 2. 去除标点符号
# 使用正则表达式 [^a-zA-Z\s] 匹配所有非字母和非空格的字符
reviews_df['review_clean'] = reviews_df['review_clean'].str.replace('[^a-z\s]', '', regex=True)
# 3. 处理缺失值
# fillna() 可以填充 NaN,然后我们再对填充后的字符串进行处理
# 或者直接在 str 方法中处理,但更清晰的做法是先填充
reviews_df['review_clean'] = reviews_df['review_clean'].fillna('no review')
print(reviews_df)
输出:
id review review_clean
0 1 This product is AMAZING!!! this product is amazing
1 2 it is okay not great. it is okay not great
2 3 Worst purchase EVER DO NOT BUY. worst purchase ever do not buy
3 4 Good value for money. good value for money
4 5 NaN no review
进阶技巧
1 链式操作 (Method Chaining)
Pandas 的 .str 方法返回一个新的 Series,因此你可以将它们像链条一样连接起来,使代码更简洁、易读。
# 不使用链式操作
df['temp'] = df['review'].str.lower()
df['temp'] = df['temp'].str.replace('!', '')
df['temp'] = df['temp'].str.replace('.', '')
df['temp'] = df['temp'].str.replace(',', '')
# ... 这样很繁琐
# 使用链式操作
df['review_chained'] = (df['review']
.str.lower()
.str.replace('[^a-z\s]', '', regex=True) # 一次性替换所有非字母字符
.str.strip() # 最后再去除两端空格
)
print(df[['review', 'review_chained']])
2 结合 apply 和自定义函数
当 .str 提供的方法无法满足你的复杂需求时,你可以结合 apply 和一个自定义的 Python 函数。
注意: apply 会比纯 .str 方法慢,因为它在 Python 层面循环,只在必要时使用。
示例: 创建一个函数,判断评论是正面、负面还是中性。
def sentiment(text):
if pd.isna(text):
return 'neutral'
text = text.lower()
if 'amazing' in text or 'good' in text:
return 'positive'
elif 'worst' in text or 'bad' in text:
return 'negative'
else:
return 'neutral'
# 使用 apply
reviews_df['sentiment'] = reviews_df['review'].apply(sentiment)
print(reviews_df[['review', 'sentiment']])
| 任务 | 推荐方法 |
|---|---|
| 大小写转换/去除空格 | .str.lower(), .str.upper(), .str.strip() |
| 拆分字符串 | .str.split() + .str.get() |
| 简单替换/检查 | .str.replace(), .str.contains(), .str.startswith() |
| 复杂模式匹配/提取 | .str.extract(), .str.findall() (配合正则表达式) |
| 计算长度/计数 | .str.len(), .str.count() |
| 复杂、多步骤清洗 | 链式操作 (df['col'].str.method1().str.method2()) |
| 高度自定义的逻辑 | df['col'].apply(your_custom_function) |
掌握 Pandas 的 .str 访问器是进行数据清洗和文本分析的关键技能,它高效、强大,并且能让你用简洁的代码完成复杂的文本处理任务。
