You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中如何基于列表列的包含条件合并DataFrame

高效关联两个DataFrame的向量化方案

需求说明

我有两个DataFrame:

  • DataFrame 1包含antecedents(前置元素组)和consequents(结果元素)列
  • DataFrame 2包含Invoice、Customer ID、StockCode(商品代码列表)列

需要实现:当DataFrame 1中antecedents的所有元素都存在于DataFrame 2的StockCode列表中时,将两个DataFrame进行关联。当前用嵌套循环实现的方案效率极低,无法适配大数据集,急需更高效的向量化实现。

数据示例

DataFrame 1示例

import pandas as pd
df1 = pd.DataFrame( {'antecedents' : [('20679'), ('85048'), ('22143'), ('22065','22138'), ('20754','21035','22041')],
               'consequents' : [('20676'), ('20719'), ('22355'), ('20724'), ('212212')]
})

DataFrame 2示例

df2 = pd.DataFrame( {'Customer ID' : [13085, 13078, 15362, 18102, 12682, 18087, 18087, 13635, 14110],
               'StockCode' : [
                           ['85048', '79323P', '79323W', '22041', '21232', '22064'], ['22350', '22349', '22195', '22353'], ['48173C', '21755', '21754', '84879', '22119', '22142'],
                             ['22143', '22145', '22130', '21364', '21360', '21351'], ['21329', '21252', '21100', '21033', '20711', '21410'], ['22065', '22138', '22139', '22352', '85014A', '85014B'],
                              ['22321', '22138', '84029E', '22111'], ['21955', '22111', '22296', '84899E', '22271', '22272'],['20754', '21035', '22041', '82001S', '82580', '85150']
                             ]  
})

当前低效循环实现

ant_list = df1['antecedents'].tolist()
df_grouped = df2.copy()

for list2 in ant_list:
    for item, row in df_grouped.iterrows():
        col_name = str(list2)
        if all(elem in row['StockCode'] for elem in list2):
            df_grouped.loc[item,col_name] = 1

高效向量化解决方案

步骤1:统一转换为集合格式

集合的子集判断操作比逐个元素遍历快得多,先把两个DataFrame中的元素组/列表转为集合:

# 处理df1的antecedents:单个元素转为单元素集合,元组转为对应集合
df1['antecedents_set'] = df1['antecedents'].apply(lambda x: set(x) if isinstance(x, tuple) else set([x]))
# 处理df2的StockCode列表
df2['stock_set'] = df2['StockCode'].apply(set)

步骤2:批量判断并关联

方案A:基于itertools的批量筛选

适合中等规模数据集,代码直观:

import itertools

# 生成df1和df2所有行的组合
row_combinations = itertools.product(df1.itertuples(index=False), df2.itertuples(index=False))

# 筛选符合条件的组合并收集结果
matched_rows = []
for df1_row, df2_row in row_combinations:
    if df1_row.antecedents_set.issubset(df2_row.stock_set):
        matched_rows.append({
            'Customer ID': df2_row['Customer ID'],
            'StockCode': df2_row.StockCode,
            'antecedents': df1_row.antecedents,
            'consequents': df1_row.consequents
        })

# 转为最终结果DataFrame
result_df = pd.DataFrame(matched_rows)

方案B:基于Numpy广播的向量化判断

适合超大数据集,利用Numpy的向量化运算进一步提升效率:

import numpy as np

# 将集合列转为Numpy数组
ant_sets = df1['antecedents_set'].to_numpy()
stock_sets = df2['stock_set'].to_numpy()

# 创建布尔矩阵:每一行对应df1的一个antecedent,每一列对应df2的一个StockCode集合
# 矩阵值为True表示该antecedent是对应StockCode集合的子集
match_mask = np.array([[ant_set.issubset(stock_set) for stock_set in stock_sets] for ant_set in ant_sets])

# 获取所有符合条件的行索引对
df1_idx, df2_idx = np.where(match_mask)

# 关联两个DataFrame的对应行
result_df = pd.concat([
    df1.loc[df1_idx].reset_index(drop=True),
    df2.loc[df2_idx].reset_index(drop=True)
], axis=1)

# 可选:删除中间生成的集合列
result_df = result_df.drop(['antecedents_set', 'stock_set'], axis=1)

性能优化说明

  • 集合的issubset操作时间复杂度为O(len(antecedents)),远低于循环逐个判断元素的O(len(antecedents)*len(StockCode))
  • 两种方案都避免了嵌套循环的低效遍历,底层依赖Python/C扩展实现,比纯Python循环快10~100倍(根据数据规模而定)
  • 超大数据集可结合分块处理,将df2拆分为多个小批次,分别与df1关联后合并结果,降低内存占用

内容的提问来源于stack exchange,提问作者sapehi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 23:35:19