如何将Pandas DataFrame中含回车的单元格拆分为多行?
解决方案
首先,你遇到的第一个错误是代码里的低级失误:计算拆分长度时用了split(','),但实际分隔符是\r,这导致lens的计算完全错误,进而引发数组长度不匹配的报错。
第二个错误是因为实际数据中Name和Age的组合存在重复,设置为索引后出现非唯一多级索引,apply+explode无法处理这种情况。
下面针对你的需求提供两种可行方案:
方案一:过滤无效值后批量拆分展开
这个方案会先去掉拆分后产生的空字符串、纯空格内容,再将每个列的有效元素展开为新行,其他列重复原行数据。如果同一行多个列拆分后的有效元素长度不一致,会生成所有元素的组合(笛卡尔积)。
import pandas as pd # 定义拆分并清理无效值的函数 def split_clean(s): # 按\r拆分,去除空字符串和纯空格内容 return [item.strip() for item in s.split('\r') if item.strip()] # 复制原DataFrame避免修改原始数据 df_clean = df.copy() # 对需要拆分的列应用拆分清理函数 split_cols = ['Roll No per Class', 'Highest Scores'] for col in split_cols: df_clean[col] = df_clean[col].apply(split_clean) # 依次对每个拆分列执行explode for col in split_cols: df_clean = df_clean.explode(col, ignore_index=True) print(df_clean)
运行示例数据后会得到:
Roll No per Class Name Age Highest Scores 0 8 tom 10 55 1 8 tom 10 62 2 8 tom 10 75 3 18 nick 15 77 4 18 nick 15 25 5 18 nick 15 85 6 9 nick 15 77 7 9 nick 15 25 8 9 nick 15 85 9 17 juli 14 55 10 19 juli 14 55 11 18 juli 14 55 12 17 juli 14 75 13 19 juli 14 75 14 18 juli 14 75 15 17 juli 14 85 16 19 juli 14 85 17 18 juli 14 85
方案二:按位置对齐拆分元素(一一对应)
如果你的数据中,每行的Roll No per Class和Highest Scores拆分后的元素是一一对应的(比如第一个学号对应第一个分数),可以用这个方案,长度不一致时会用NaN补全:
import pandas as pd import numpy as np def split_clean(s): return [item.strip() for item in s.split('\r') if item.strip()] # 对需要拆分的列应用函数 df['Roll Clean'] = df['Roll No per Class'].apply(split_clean) df['Scores Clean'] = df['Highest Scores'].apply(split_clean) # 对每行的拆分结果按位置对齐,生成新行 result = df.explode(['Roll Clean', 'Scores Clean'], ignore_index=True) # 替换空值并还原原列名 result = result.rename(columns={'Roll Clean': 'Roll No per Class', 'Scores Clean': 'Highest Scores'}) result = result.drop(columns=['Roll No per Class', 'Highest Scores'], axis=1).rename(columns={'Roll Clean': 'Roll No per Class', 'Scores Clean': 'Highest Scores'}) # 处理长度不一致的情况,补全缺失值 max_len = result.groupby(level=0).size().max() result = result.reindex(pd.MultiIndex.from_product([result.index.unique(), range(max_len)], names=['orig_idx', 'pos'])) result['Name'] = result['Name'].ffill() result['Age'] = result['Age'].ffill() result = result.dropna(subset=['Roll No per Class', 'Highest Scores'], how='all').reset_index(drop=True) print(result)
关键注意事项
- 优先清理拆分后的无效值(空字符串、纯空格),这是解决长度不匹配的核心前提。
- 如果数据量很大(15000行),方案一的效率更高,因为
explode是Pandas内置的高效操作。 - 若实际数据中每行的拆分元素是一一对应的,务必使用方案二,避免生成不必要的冗余数据。
内容的提问来源于stack exchange,提问作者Beginner_profile
相关产品推荐
相关产品推荐

