如何用纯Pandas高效创建关联购买商品的查找表?
用纯Pandas高效实现商品关联购买查找表
你的暴力循环方法虽然直观,但在数据量较大时效率会很低——iterrows()本身就不是高性能的遍历方式,嵌套循环更是会让时间复杂度飙升。下面提供两种纯Pandas的高效实现方案,性能和代码优雅度都更优:
方案一:基于自连接的纯Pandas实现
这种方法利用Pandas的merge操作完成同一发票内的商品配对,完全避免Python层面的循环:
import pandas as pd df = pd.DataFrame({ "Invoice": [1, 1, 2, 3, 4, 4, 4, 5, 5], "Item": ["Apple", "Pear", "Banana", "Apple", "Apple", "Orange", "Pear", "Apple", "Orange"] }) # 1. 添加临时列用于按发票自连接 df_temp = df.assign(temp=df["Invoice"]) # 2. 按发票字段自连接,得到同一发票下的所有商品组合 joined_df = df_temp.merge(df_temp, on="temp", suffixes=("_key", "_value")) # 3. 过滤掉商品自身配对的行,整理成目标格式 lookup_table = ( joined_df[joined_df["Item_key"] != joined_df["Item_value"]] .rename(columns={"Item_key": "key", "Item_value": "value"}) [["key", "value"]] .reset_index(drop=True) ) print(lookup_table)
方案二:结合分组与组合生成(需itertools辅助)
如果想更清晰地控制商品配对逻辑,可以先按发票分组,再生成每组内的商品组合,最后展开结果:
import pandas as pd from itertools import combinations df = pd.DataFrame({ "Invoice": [1, 1, 2, 3, 4, 4, 4, 5, 5], "Item": ["Apple", "Pear", "Banana", "Apple", "Apple", "Orange", "Pear", "Apple", "Orange"] }) # 1. 按发票分组,生成每组内的无序商品两两组合 grouped_pairs = df.groupby("Invoice")["Item"].apply(lambda x: list(combinations(x, 2))) # 2. 展开所有组合并转为key-value格式 lookup_table = grouped_pairs.explode().apply(pd.Series).rename(columns={0: "key", 1: "value"}) # 3. 添加反向配对(和原代码逻辑一致,保留双向关联) reverse_pairs = lookup_table.rename(columns={"key": "value", "value": "key"}) lookup_table = pd.concat([lookup_table, reverse_pairs]).reset_index(drop=True) print(lookup_table)
为什么这两种方法更优?
- 性能提升:Pandas的
merge和分组操作都是基于C语言实现的内部优化,比Python循环快几个数量级,数据量越大优势越明显。 - 代码简洁:用链式调用和内置操作替代嵌套循环,逻辑更清晰,可读性更强。
- 可扩展性:后续如果需要调整配对规则(比如只保留唯一配对、统计关联次数),可以直接在现有代码上修改,无需重构循环逻辑。
内容的提问来源于stack exchange,提问作者DanneP
相关产品推荐
相关产品推荐

