如何识别DataFrame中合同间的关联关系
合同关联关系提取问题
原始数据
我有一个包含订单及合同编号的DataFrame:
| Orders | Contract |
|---|---|
| Order_1 | Contract_1 |
| Order_1 | Contract_2 |
| Order_2 | Contract_1 |
| Order_2 | Contract_2 |
合同可关联多个订单,订单也可关联多个合同。
需求
希望获取所有合同间的关联关系,生成以所有合同为索引、其他列展示关联合同的DataFrame,期望输出为以下两种形式之一:
形式一:逗号分隔关联合同
| Contract_source | Contract_link |
|---|---|
| Contract_1 | Contract_2, Contract_3 |
| Contract_2 | Contract_1, Contract_3 |
| Contract_3 | Contract_1, Contract_2 |
| Contract_4 | Contract_8 |
形式二:多列展示关联合同
| Contract_source | Contract_link_1 | Contract_link_2 |
|---|---|---|
| Contract_1 | Contract_2 | Contract_3 |
| Contract_2 | Contract_1 | Contract_3 |
| Contract_3 | Contract_1 | Contract_2 |
| Contract_4 | Contract_8 |
已尝试的操作
我已生成一个以订单为索引、合同为列的DataFrame:
df_po = pd.DataFrame(df.loc[:,['Contract Nbr', 'Order']].groupby(by='Order')\ ['Contract Nbr'].apply(lambda x : list(x.unique()))).reset_index()
对应的表格:
| Orders_source | Contract_link |
|---|---|
| Order_1 | Contract_1, Contract_2 |
| Order_2 | Contract_3, Contract_4 |
还生成了一个以合同为索引、订单为列的DataFrame:
df_contract = pd.DataFrame(df.loc[:,['Contract Nbr', 'Order']].groupby(by='Contract Nbr')\ ['Order'].apply(lambda x : x.unique())).reset_index()
对应的表格:
| Contract_source | orders_link |
|---|---|
| Contract_1 | Order_1, Order_2 |
| Contract_2 | Order_3, Order_4 |
尝试创建订单转合同的字典,但写法有误:
dict_orders_to_contract = zip(df_po['Order'], df_po['Contrct Nbr'])
并尝试替换,但代码无法运行:
df_contract['count PO'] = pd.DataFrame(df.loc[:,['Contract Nbr', 'Order']].groupby(by='Contract Nbr')\ ['Order'].apply(lambda x : x.unique().replace(dict_orders_to_contract ))).reset_index()['Order']
解决方案
步骤1:构建正确的订单-合同映射字典
先修正字典的创建逻辑,让每个订单对应其关联的所有合同列表:
# 构建订单到关联合同列表的字典 dict_order_to_contracts = df_po.set_index('Order')['Contract Nbr'].to_dict()
步骤2:获取每个合同的关联合同
对每个合同,先找到它绑定的所有订单,再通过字典找到这些订单对应的全部合同,最后去重并排除合同自身:
def get_linked_contracts(row): current_contract = row['Contract_source'] linked_orders = row['orders_link'] # 收集所有关联订单对应的合同 all_related_contracts = [] for order in linked_orders: all_related_contracts.extend(dict_order_to_contracts[order]) # 去重并移除当前合同本身 unique_links = list(set(all_related_contracts) - {current_contract}) return unique_links # 修正df_contract的列名 df_contract = df_contract.rename(columns={'Contract Nbr': 'Contract_source', 'Order': 'orders_link'}) # 应用函数生成关联合同列 df_contract['Contract_link'] = df_contract.apply(get_linked_contracts, axis=1)
步骤3:转换为期望的输出形式
形式一:逗号分隔字符串
df_form1 = df_contract[['Contract_source', 'Contract_link']].copy() df_form1['Contract_link'] = df_form1['Contract_link'].apply(lambda x: ', '.join(x) if x else '')
形式二:多列展示
先找到最大的关联合同数量,再拆分列表为多列:
max_link_count = df_contract['Contract_link'].apply(len).max() # 生成列名 link_col_names = [f'Contract_link_{i+1}' for i in range(max_link_count)] # 将列表拆分为多列 link_columns = df_contract['Contract_link'].apply(pd.Series) link_columns.columns = link_col_names # 合并到原DataFrame df_form2 = pd.concat([df_contract[['Contract_source']], link_columns], axis=1)
完整可运行代码
import pandas as pd # 原始数据 df = pd.DataFrame({ 'Orders': ['Order_1', 'Order_1', 'Order_2', 'Order_2'], 'Contract': ['Contract_1', 'Contract_2', 'Contract_1', 'Contract_2'] }) # 重命名列匹配代码中的命名 df = df.rename(columns={'Orders': 'Order', 'Contract': 'Contract Nbr'}) # 生成订单-合同映射表 df_po = df.groupby('Order')['Contract Nbr'].apply(lambda x: list(x.unique())).reset_index() # 生成合同-订单映射表 df_contract = df.groupby('Contract Nbr')['Order'].apply(lambda x: list(x.unique())).reset_index() df_contract = df_contract.rename(columns={'Contract Nbr': 'Contract_source', 'Order': 'orders_link'}) # 构建订单到合同的字典 dict_order_to_contracts = df_po.set_index('Order')['Contract Nbr'].to_dict() # 定义获取关联合同的函数 def get_linked_contracts(row): current_contract = row['Contract_source'] linked_orders = row['orders_link'] all_related_contracts = [] for order in linked_orders: all_related_contracts.extend(dict_order_to_contracts[order]) unique_links = list(set(all_related_contracts) - {current_contract}) return unique_links # 生成关联合同列 df_contract['Contract_link'] = df_contract.apply(get_linked_contracts, axis=1) # 生成形式一结果 df_form1 = df_contract[['Contract_source', 'Contract_link']].copy() df_form1['Contract_link'] = df_form1['Contract_link'].apply(lambda x: ', '.join(x) if x else '') # 生成形式二结果 max_link_count = df_contract['Contract_link'].apply(len).max() link_col_names = [f'Contract_link_{i+1}' for i in range(max_link_count)] link_columns = df_contract['Contract_link'].apply(pd.Series) link_columns.columns = link_col_names df_form2 = pd.concat([df_contract[['Contract_source']], link_columns], axis=1) # 打印结果 print("形式一输出:") print(df_form1) print("\n形式二输出:") print(df_form2)
内容的提问来源于stack exchange,提问作者Briac
相关产品推荐
相关产品推荐

