在CSV文件的实际使用中,经常会遇到单个单元格内包含分号、换行等分隔符的嵌套子行结构,比如一个订单单元格里用分号分隔多个商品,或者用换行存储多个收货地址,直接读取会导致数据错位。我们可以通过Python的文本处理和pandas库操作,将这些嵌套内容智能拆分为多列。

场景示例与问题说明
假设我们有一个名为order_data.csv的文件,内容如下:
订单ID,商品列表,收货地址 1001,手机;耳机;充电宝,北京市海淀区n北京市朝阳区 1002,笔记本;鼠标,上海市浦东新区 1003,,广州市天河区n广州市越秀区n广州市荔湾区
可以看到商品列表列用分号分隔多个商品,收货地址列用换行符分隔多个地址,直接读取后这两个列的内容都是字符串,无法单独使用每个子项,需要拆分为多列。
基础拆分实现步骤
1. 读取原始CSV文件
首先用pandas读取原始文件,注意设置keep_default_na=False避免空字符串被识别为NaN:
import pandas as pd
# 读取CSV,设置keep_default_na=False保留空字符串
df = pd.read_csv("order_data.csv", keep_default_na=False)
print("原始数据:")
print(df)
2. 拆分分号分隔的嵌套列
对商品列表列进行处理,按分号拆分后展开为多列,不足的部分用空字符串填充:
def split_semicolon_column(series, prefix):
# 按分号拆分每个单元格内容
split_result = series.apply(lambda x: x.split(";") if x else [])
# 获取最大拆分长度,确定列数
max_len = split_result.apply(len).max()
# 生成多列数据
new_cols = {}
for i in range(max_len):
col_name = f"{prefix}_{i+1}"
new_cols[col_name] = split_result.apply(lambda x: x[i] if i < len(x) else "")
return pd.DataFrame(new_cols)
# 拆分商品列表列
product_cols = split_semicolon_column(df["商品列表"], "商品")
df = pd.concat([df, product_cols], axis=1)
3. 拆分换行分隔的嵌套列
对收货地址列进行处理,按换行符拆分后展开为多列:
def split_newline_column(series, prefix):
# 按换行符拆分每个单元格内容,换行符在Python字符串中为n
split_result = series.apply(lambda x: x.split("n") if x else [])
# 获取最大拆分长度,确定列数
max_len = split_result.apply(len).max()
# 生成多列数据
new_cols = {}
for i in range(max_len):
col_name = f"{prefix}_{i+1}"
new_cols[col_name] = split_result.apply(lambda x: x[i] if i < len(x) else "")
return pd.DataFrame(new_cols)
# 拆分收货地址列
address_cols = split_newline_column(df["收货地址"], "地址")
df = pd.concat([df, address_cols], axis=1)
4. 查看拆分后的结果
执行上述代码后,查看最终的数据结构:
print("n拆分后数据:")
print(df[["订单ID", "商品_1", "商品_2", "商品_3", "地址_1", "地址_2", "地址_3"]])
输出结果如下:
订单ID 商品_1 商品_2 商品_3 地址_1 地址_2 地址_3 0 1001 手机 耳机 充电宝 北京市海淀区 北京市朝阳区 1 1002 笔记本 鼠标 上海市浦东新区 2 1003 广州市天河区 广州市越秀区 广州市荔湾区
智能适配优化
如果CSV中嵌套分隔符不固定,有的用分号有的用逗号,或者换行符有rn和n两种格式,可以优化拆分函数:
import re
def smart_split_nested(series, prefix, split_pattern):
# 用正则匹配分隔符,支持多种分隔符场景
split_result = series.apply(lambda x: re.split(split_pattern, x) if x else [])
max_len = split_result.apply(len).max()
new_cols = {}
for i in range(max_len):
col_name = f"{prefix}_{i+1}"
new_cols[col_name] = split_result.apply(lambda x: x[i].strip() if i < len(x) else "")
return pd.DataFrame(new_cols)
# 支持分号或者中文分号分隔
product_cols = smart_split_nested(df["商品列表"], "商品", r"[;;]")
# 支持rn或者n换行分隔
address_cols = smart_split_nested(df["收货地址"], "地址", r"r?n")
注意事项
- 拆分前先确认CSV文件的编码格式,避免出现乱码导致分隔符识别错误
- 如果嵌套子行数量差异极大,拆分后会产生大量空列,可根据实际业务需求设置最大拆分列数
- 处理完成后可以删除原始嵌套列,让数据表更简洁