Pandas展开多列列表遇阻,求适配不等长列表的解决方案
问题描述
我已经尝试过站内所有相关方法但均无效,请不要标记为重复问题,当前问题存在特殊性。
我有如下格式的JSON数据(包含500条重复结构的Id数据,还有其他非列表类型列):
[ { "Id": 1, "Design": ["09", "10", "13"], "Research": ["Eng", "Math"] } ]
我需要展开其中的列表列,最终输出为Excel文件,无论直接处理JSON还是用Pandas均可。
已尝试的方法及问题
自定义函数方法:
def lenx(x): return len(x) if isinstance(x,(list, tuple, np.ndarray, pd.Series)) else 1 def cell_size_equalize2(row, cols='', fill_mode='internal', fill_value=''): jcols = [j for j,v in enumerate(row.index) if v in cols] if len(jcols)<1: jcols = range(len(row.index)) Ls = [lenx(x) for x in row.values] if not Ls[:-1]==Ls[1:]: vals = [v if isinstance(v,list) else [v] for v in row.values] if fill_mode=='external': vals = [[e] + [fill_value]*(max(Ls)-1) if (not j in jcols) and (isinstance(row.values[j],list)) else e + [fill_value]*(max(Ls)-lenx(e)) for j,e in enumerate(vals)] elif fill_mode == 'internal': vals = [[e]+[e]*(max(Ls)-1) if (not j in jcols) and (isinstance(row.values[j],list)) else e+[e[-1]]*(max(Ls)-lenx(e)) for j,e in enumerate(vals)] else: vals = [e[0:min(Ls)] for e in vals] row = pd.Series(vals,index=row.index.tolist()) return row运行后引发索引错误。
Pandas
explode多列方法:df.explode(['B', 'C', 'D', 'E']).reset_index(drop=True)提示列必须长度相同。
逐列展开后拼接方法:
df1 = pd.concat([df[x].explode().to_frame() .assign(g=lambda x: x.groupby(level=0).cumcount()) .set_index('g', append=True) for x in cols_to_explode], axis=1)生成大量冗余行,疑似因逐列展开导致内存错误。
期望输出格式
| Id | Design | Research |
|---|---|---|
| 1 | 09 | Eng |
| 1 | 10 | Math |
| 1 | 13 |
解决方案
方案一:Pandas 处理(推荐)
核心思路是对每个列表列单独展开并保留分组计数,再按分组和原始索引合并,最后填充空值并整理:
import pandas as pd # 读取JSON数据(假设文件名为data.json) df = pd.read_json('data.json') # 指定需要展开的列表列 cols_to_explode = ['Design', 'Research'] # 为每个列表列生成带分组计数的DataFrame exploded_dfs = [] for col in cols_to_explode: exploded = df[col].explode().reset_index() exploded['group'] = exploded.groupby('index').cumcount() exploded_dfs.append(exploded.pivot(index=['index', 'group'], columns='level_1', values=col).reset_index()) # 合并所有展开后的DataFrame merged = exploded_dfs[0] for df_exp in exploded_dfs[1:]: merged = pd.merge(merged, df_exp, on=['index', 'group'], how='outer') # 合并原始DataFrame中的非列表列 final_df = pd.merge(df.drop(cols_to_explode, axis=1), merged, left_index=True, right_on='index').drop(['index', 'group'], axis=1) # 重置索引并保存为Excel final_df.reset_index(drop=True).to_excel('output.xlsx', index=False)
方案二:直接处理JSON生成结构化数据
如果Pandas内存压力大,可以直接遍历JSON数据生成目标格式的列表,再转成DataFrame:
import pandas as pd import json # 读取JSON数据 with open('data.json', 'r') as f: data = json.load(f) # 指定需要展开的列表列 cols_to_explode = ['Design', 'Research'] # 生成目标结构的列表 output_data = [] for item in data: # 获取非列表字段 non_list_fields = {k: v for k, v in item.items() if not isinstance(v, list)} # 找到最长的列表列长度 max_len = max(len(v) for k, v in item.items() if isinstance(v, list)) # 逐行生成数据 for i in range(max_len): row = non_list_fields.copy() for col in cols_to_explode: row[col] = item[col][i] if i < len(item[col]) else None output_data.append(row) # 转成DataFrame并保存 pd.DataFrame(output_data).to_excel('output.xlsx', index=False)
这两种方案都能处理列表列长度不一致的情况,不会生成冗余行,适配500条数据的规模。
内容的提问来源于stack exchange,提问作者Federicofkt
相关产品推荐
相关产品推荐

