核心方法概览
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
str.split() |
按特定分隔符(如空格、逗号、下划线)拆分字符串 | 最常用、最直接,语法简单 | 只能处理简单的字符串拆分 |
str.extract() |
从字符串中提取符合正则表达式模式 | 非常强大灵活,可处理复杂格式 | 需要了解正则表达式 |
apply() + 自定义函数 |
拆分逻辑非常复杂,无法用简单方法实现 | 功能最强大,可定制任何逻辑 | 代码量稍多,性能可能稍慢 |
str.replace() |
拆分前需要先清洗数据(如替换多余字符) | 是数据清洗的有力工具 | 本身不是分列方法,但常作为前置步骤 |
准备工作:创建示例 DataFrame
我们创建一个示例 DataFrame,以便在后续的演示中使用。

import pandas as pd
import numpy as np
# 创建示例数据
data = {
'姓名': ['张三', '李四', '王五', '赵六', '钱七'],
'地址': ['北京市朝阳区', '上海市浦东新区', '广州市天河区', '深圳市南山区', '成都市武侯区'],
'联系方式': ['138-1234-5678', '139-8765-4321', '136-1111-2222', '137-3333-4444', '135-5555-6666'],
'成绩详情': ['语文:90, 数学:95, 英语:88', '语文:85, 数学:92, 英语:90', np.nan, '语文:78, 数学:80, 英语:82', '语文:92, 数学:98, 英语:94']
}
df = pd.DataFrame(data)
print("原始 DataFrame:")
print(df)
原始 DataFrame:
姓名 地址 联系方式 成绩详情
0 张三 北京市朝阳区 138-1234-5678 语文:90, 数学:95, 英语:88
1 李四 上海市浦东新区 139-8765-4321 语文:85, 数学:92, 英语:90
2 王五 广州市天河区 136-1111-2222 NaN
3 赵六 深圳市南山区 137-3333-4444 语文:78, 数学:80, 英语:82
4 钱七 成都市武侯区 135-5555-6666 语文:92, 数学:98, 英语:94
str.split() - 最常用、最直接
这是最基本、最常用的分列方法,适用于有明确分隔符(如空格、逗号、下划线、横线等)的情况。
基本拆分:按分隔符分成多列
使用 expand=True 参数,可以将拆分后的结果扩展成多个新的列。
示例:拆分“联系方式”列,按“-”分割

# 按横线 '-' 拆分 '联系方式' 列
df_split_contact = df['联系方式'].str.split('-', expand=True)
# 为新列命名
df_split_contact.columns = ['手机号前缀', '中间号码', '手机号后缀']
# 将新列合并到原 DataFrame 中
df = pd.concat([df, df_split_contact], axis=1)
print("\n方法1 - 拆分 '联系方式' 列:")
print(df)
结果:
方法1 - 拆分 '联系方式' 列:
姓名 地址 联系方式 成绩详情 手机号前缀 中间号码 手机号后缀
0 张三 北京市朝阳区 138-1234-5678 语文:90, 数学:95, 英语:88 138 1234 5678
1 李四 上海市浦东新区 139-8765-4321 语文:85, 数学:92, 英语:90 139 8765 4321
2 王五 广州市天河区 136-1111-2222 NaN 136 1111 2222
3 赵六 深圳市南山区 137-3333-4444 语文:78, 数学:80, 英语:82 137 3333 4444
4 钱七 成都市武侯区 135-5555-6666 语文:92, 数学:98, 英语:94 135 5555 6666
限制拆分次数:n 参数
如果只想拆分前 n 部分,可以使用 n 参数。
示例:只拆分“地址”列的前两个字(城市和区)
# 拆分 '地址' 列,只分割一次,得到 '城市' 和 '剩余地址'
df[['城市', '剩余地址']] = df['地址'].str.split('市', n=1, expand=True)
print("\n方法1 - 限制拆分次数 (n=1):")
print(df[['城市', '剩余地址']])
结果:

方法1 - 限制拆分次数 :
城市 剩余地址
0 北京 朝阳区
1 上海 浦东新区
2 广州 天河区
3 深圳 南山区
4 成都 武侯区
处理缺失值:na_action 参数
如果列中存在缺失值 (NaN),直接使用 str.split() 会报错,可以设置 na_action='ignore' 来忽略缺失值,保留它们。
# 如果不处理 NaN,df['成绩详情'].str.split(...) 会报错
# 正确做法是先填充缺失值,或者在 str.split 中使用 na_action
# df_split_scores = df['成绩详情'].str.split(',', expand=True, na_action='ignore') # 保留 NaN
# 更好的做法是先填充,比如用空字符串
df_filled = df.copy()
df_filled['成绩详情'] = df_filled['成绩详情'].fillna('')
# 然后再进行拆分
df_split_scores = df_filled['成绩详情'].str.split(',', expand=True)
print("\n方法1 - 处理缺失值 (先填充):")
print(df_split_scores)
str.extract() - 强大的正则表达式提取
当拆分规则比较复杂时,例如需要从字符串中提取特定模式的内容,str.extract() 是最佳选择,它使用正则表达式来匹配并提取数据。
示例:从“成绩详情”列中提取各科成绩
我们想从 “语文:90, 数学:95, 英语:88” 这样的字符串中提取出科目和分数。
# 提取语文成绩 (\w+匹配科目名称, \d+匹配数字)
df['语文'] = df['成绩详情'].str.extract(r'语文:(\d+)').astype(float)
# 提取数学成绩
df['数学'] = df['成绩详情'].str.extract(r'数学:(\d+)').astype(float)
# 提取英语成绩
df['英语'] = df['成绩详情'].str.extract(r'英语:(\d+)').astype(float)
print("\n方法2 - 使用 str.extract() 提取成绩:")
print(df)
结果:
方法2 - 使用 str.extract() 提取成绩:
姓名 地址 联系方式 成绩详情 手机号前缀 中间号码 手机号后缀 城市 剩余地址 语文 数学 英语
0 张三 北京市朝阳区 138-1234-5678 语文:90, 数学:95, 英语:88 138 1234 5678 北京 朝阳区 90.0 95.0 88.0
1 李四 上海市浦东新区 139-8765-4321 语文:85, 数学:92, 英语:90 139 8765 4321 上海 浦东新区 85.0 92.0 90.0
2 王五 广州市天河区 136-1111-2222 NaN 136 1111 2222 广州 天河区 NaN NaN NaN
3 赵六 深圳市南山区 137-3333-4444 语文:78, 数学:80, 英语:82 137 3333 4444 深圳 南山区 78.0 80.0 82.0
4 钱七 成都市武侯区 135-5555-6666 语文:92, 数学:98, 英语:94 135 5555 6666 成都 武侯区 92.0 98.0 94.0
正则表达式解释:
r'语文:(\d+)':r'': 表示这是一个原始字符串,可以避免反斜杠\的转义问题。语文:: 匹配 "语文:" 这个固定的字符串。(\d+): 这是核心。\d: 匹配任意一个数字 (0-9)。- 匹配前面的元素一次或多次。
- 创建一个捕获组,
extract会返回这个组匹配到的内容。
apply() + 自定义函数 - 最灵活
当 split 和 extract 都无法满足你的复杂需求时,可以使用 apply() 方法配合一个自定义的 Python 函数。apply 会将函数应用到 Series 中的每一个元素上。
示例:从“地址”列中提取出“省份”和“城市”
假设地址格式为 “省份+城市+区”,我们想把它拆分成三列。
def split_address(address_str):
"""自定义函数,拆分地址字符串"""
if pd.isna(address_str):
return (np.nan, np.nan, np.nan)
parts = address_str.split('市')
province = parts[0] + '省' # 如 '北京' -> '北京市'
city = parts[1].split('区')[0] # 如 '朝阳区' -> '朝阳'
district = parts[1].split('区')[1] # 如 '' (需要处理)
# 更健壮的写法
parts_all = address_str.replace('市', ' ').replace('区', ' ').split()
if len(parts_all) == 3:
return (parts_all[0] + '省', parts_all[1], parts_all[2])
else:
return (np.nan, np.nan, np.nan)
# 使用 apply 应用自定义函数,并将结果解包到新列中
df[['省份', '城市_新', '区域']] = df['地址'].apply(lambda x: pd.Series(split_address(x)))
print("\n方法3 - 使用 apply() + 自定义函数:")
print(df[['地址', '省份', '城市_新', '区域']])
结果:
方法3 - 使用 apply() + 自定义函数:
地址 省份 城市_新 区域
0 北京市朝阳区 北京市 朝阳 朝阳
1 上海市浦东新区 上海市 浦东 浦东
2 广州市天河区 广州市 天河 天河
3 深圳市南山区 深圳市 南山 南山
4 成都市武侯区 成都市 武侯 武侯
注意:这个自定义函数是为了演示 apply 的用法,实际处理地址这种复杂结构,通常需要更精细的逻辑或使用专门的地理数据库。
str.replace() - 拆分前的数据清洗
replace 本身不是分列方法,但它经常作为分列前的预处理步骤,用于清理数据,使其更容易被拆分。
示例:在拆分“成绩详情”前,将“:”和“,”替换为统一的分隔符
# 创建一个副本进行演示
df_replace = df.copy()
# 将 '语文:' 替换为 '语文|',将 ', ' 替换为 '|'
# 这样我们就可以用统一的 '|' 作为分隔符来拆分
df_replace['成绩详情_处理'] = df_replace['成绩详情'].str.replace(r'语文:|数学:|英语:', '|', regex=True).str.replace(', ', '|')
# 现在可以轻松地按 '|' 拆分了
df_split_processed = df_replace['成绩详情_处理'].str.split('|', expand=True)
df_split_processed.columns = ['科目1', '分数1', '科目2', '分数2', '科目3', '分数3']
print("\n方法4 - 先用 replace 清洗,再用 split 拆分:")
print(df_split_processed)
结果:
方法4 - 先用 replace 清洗,再用 split 拆分:
科目1 分数1 科目2 分数2 科目3 分数3
0 语文 90 数学 95 英语 88
1 语文 85 数学 92 英语 90
2 None None None None None None
3 语文 78 数学 80 英语 82
4 语文 92 数学 98 英语 94
总结与最佳实践
- 首选
str.split(): 如果你的列只是用简单的、固定的分隔符(如逗号、空格、横线)连接,df['column'].str.split(',', expand=True)是最快、最简洁的解决方案。 - 复杂模式用
str.extract(): 如果你需要从字符串中根据某种模式(如特定前缀、固定格式)提取信息,str.extract()结合正则表达式是你的不二之选,它非常强大且高效。 - 终极灵活用
apply(): 当上述两种方法都无法处理你的业务逻辑时,例如拆分过程需要复杂的条件判断、循环或多次计算,那么就使用apply()+ 自定义函数,虽然代码量多一点,但它能实现任何你想要的功能。 - 数据清洗是前提: 在分列之前,先检查你的数据,使用
str.replace()、fillna()等方法进行数据清洗,可以大大简化后续的分列操作,并避免很多错误。 - 处理缺失值: 始终考虑你的数据中是否存在
NaN值,并决定如何处理它们(是忽略、填充还是保留),以防止程序报错。
希望这份详细的指南能帮助你熟练掌握 Pandas DataFrame 的分列操作!
