如何高效生成基于列表笛卡尔积的Pandas DataFrame?
高效实现Pandas列表列的笛卡尔积展开
嘿,你的这个需求我太熟悉了——把每行里的列表列做笛卡尔积配对,还要给不同列标记对应的value值。原方法用Python循环逐行追加确实效率极低,尤其是数据量大的时候,因为loc[len(new_df)]每次都会触发DataFrame的内存重新分配,而且Python循环本身就远不如Pandas的矢量化操作高效。
下面给你两种高效的优化方案,全都是基于Pandas内置的矢量化操作,完全避开Python层面的循环:
方案一:用explode分步处理(直观简洁)
这是最容易理解且高效的方式,先分别处理Yes和No的配对逻辑,再合并最终结果:
import pandas as pd # 示例数据 df = pd.DataFrame({ 'a': [[1,2,3], [7,11,6]], 'Yes': [["a","b"], ["a","d","f"]], 'No': [["A","B","C"], ["C","H","L","Z"]] }) # 处理Yes部分:展开a和Yes的笛卡尔积,标记value=1 yes_df = df.explode('a').explode('Yes').rename(columns={'Yes': 'C2'}) yes_df['value'] = 1 # 处理No部分:展开a和No的笛卡尔积,标记value=0 no_df = df.explode('a').explode('No').rename(columns={'No': 'C2'}) no_df['value'] = 0 # 合并两部分并整理列名 new_df = pd.concat([yes_df[['a', 'C2', 'value']], no_df[['a', 'C2', 'value']]], ignore_index=True) new_df = new_df.rename(columns={'a': 'C1'})
方案二:用melt+explode一次处理(更紧凑)
如果想把逻辑整合得更简洁,可以先把Yes和No列转成长格式,再一次性完成所有笛卡尔积展开:
import pandas as pd # 示例数据 df = pd.DataFrame({ 'a': [[1,2,3], [7,11,6]], 'Yes': [["a","b"], ["a","d","f"]], 'No': [["A","B","C"], ["C","H","L","Z"]] }) # 先把Yes和No转成"变量-值"的长格式 melted_df = df.melt(id_vars='a', var_name='type', value_name='C2') # 根据type列映射对应的value值 melted_df['value'] = melted_df['type'].map({'Yes': 1, 'No': 0}) # 一次性展开a和C2的笛卡尔积,整理列名 new_df = melted_df.explode('a').explode('C2')[['a', 'C2', 'value']].rename(columns={'a': 'C1'})
为什么这两种方法更快?
- 核心用到的
explode是Pandas底层优化的矢量化操作,在C语言层面处理数据,比Python循环快几个数量级。 - 完全避免了逐行追加
new_df.loc[len(new_df)]这种低效操作,而是通过Pandas的批量操作生成结果,内存分配更高效。
你可以测试一下,不管你的DataFrame规模多大,这两种方法的速度都会比原方法快很多~
内容的提问来源于stack exchange,提问作者ImAUser
相关产品推荐
相关产品推荐

