如何用Pandas按对应元素展开含嵌套列表的列?避免笛卡尔积
解决Pandas多列表列展开时的笛卡尔积问题
问题分析
你当前的代码多次调用explode(),每次调用都会把当前DataFrame的所有行按指定列的列表展开,多次调用就会产生笛卡尔积——比如你的示例中,第一次explode('gender')把1行变成4行,第二次explode('age')又把这4行每行变成4行(共16行),第三次explode('occupation')再把16行每行变成4行,最终得到4×4×4=64行,这显然不是你要的对应位置元素匹配的结果。
你需要的是将每行中多个列表列的对应索引位置的元素一一配对展开,而不是无差别组合。
解决方案
方法1:使用多列同时Explode(推荐,Pandas 1.3.0+)
从Pandas 1.3.0版本开始,explode()支持传入一个列名列表,这样会同时对多个列表列进行展开,并且保证同一行中各列表的对应位置元素匹配:
import pandas as pd # Sample data data = { 'trial_id': ['t19120109-68'], 'date': ['19120109'], 'gender': [['male', 'male', 'male', 'male']], 'age': [[24, 27, 22, 26]], 'occupation': [['coster', 'fruiterer', 'coster', 'car-man']], 'crime': ['robbery'], 'punishment': ['imprison'] } df = pd.DataFrame(data) # 同时展开多个列表列 df_exploded = df.explode(['gender', 'age', 'occupation']) print(df_exploded)
执行后会得到4行正确结果,每个列表的第i个元素对应同一行。
方法2:兼容低版本Pandas(1.3.0以下)
如果你的Pandas版本低于1.3.0,可以用apply结合pd.Series来逐行处理列表列,再拼接回原DataFrame:
import pandas as pd data = { 'trial_id': ['t19120109-68'], 'date': ['19120109'], 'gender': [['male', 'male', 'male', 'male']], 'age': [[24, 27, 22, 26]], 'occupation': [['coster', 'fruiterer', 'coster', 'car-man']], 'crime': ['robbery'], 'punishment': ['imprison'] } df = pd.DataFrame(data) # 定义处理函数:将每行的列表列转为Series,非列表列保持原值 def expand_row(row): # 提取列表列的元素,转为DataFrame list_cols = ['gender', 'age', 'occupation'] list_data = {col: row[col] for col in list_cols} expanded_list = pd.DataFrame(list_data) # 添加非列表列的内容 non_list_cols = [col for col in df.columns if col not in list_cols] for col in non_list_cols: expanded_list[col] = row[col] return expanded_list # 逐行处理并拼接 df_exploded = pd.concat([expand_row(row) for _, row in df.iterrows()], ignore_index=True) # 调整列顺序和原DataFrame一致 df_exploded = df_exploded[df.columns] print(df_exploded)
这个方法会遍历每一行,把该行的列表列按位置展开,同时复制非列表列的内容,最终合并成正确的结果。
关键注意点
- 确保所有需要展开的列表列,在每行中的列表长度一致,否则会报错或出现不匹配的情况(比如某行gender列表长度是4,age列表长度是3,就无法一一对应)。
- 多列explode时,Pandas会自动验证各列表长度是否匹配,不匹配会抛出ValueError。
内容的提问来源于stack exchange,提问作者buzzo
相关产品推荐
相关产品推荐

