如何从多份CSV的邻居列表高效构建二分邻接矩阵?
高效构建二分邻接矩阵优化方案
问题背景
我有大量CSV文件,每个文件包含两列:
id列:单文件内值唯一,多文件中相同id指代同一对象,且无单个CSV包含全部id;neighbors列:存储字符串列表,id值不会出现在该列的列表中。
需要构建类二分邻接矩阵:每行对应一个id值i,每列对应neighbors中的字符串j,只要任意CSV里id为i的行的neighbors列表包含j,单元格(i,j)设为1。
原实现代码因嵌套循环频繁修改数据框,运行耗时过长:
import pandas as pd adjacency_matrix = pd.DataFrame() list_of_csv_files = [csv_file1, csv_file2, ...] for file in list_of_csvs: df = pd.read_csv(file) df.set_index('id', inplace = True) for i in df.index: for j in df.at[i,'neighbors']: adjacency_matrix.at[i, j] = 1
示例
若数据框列表为list_of_dataframes = [df1,df2]:
df1 = pd.DataFrame(data={'id':['11','12'], 'neighbors': [['a'], ['a', 'b']]}) df2 = pd.DataFrame(data={'id':['11','13'], 'neighbors': [['c'], ['d']]})
目标结果:
a b c d 11 1 NaN 1 NaN 12 1 1 NaN NaN 13 NaN NaN NaN 1
优化思路与代码
原代码的核心问题是嵌套循环逐个修改数据框,产生大量IO开销。改用向量化操作+透视表的方式,大幅提升效率:
- 批量读取CSV,将每个
id的neighbors列表展开为多行(每个邻居对应一行); - 去重保留唯一的
id-邻居配对; - 用透视表快速生成邻接矩阵,标记存在的配对为1,缺失值保留为NaN。
import pandas as pd list_of_csv_files = [csv_file1, csv_file2, ...] # 1. 读取所有CSV并展开neighbors列 all_data = [] for file in list_of_csv_files: df = pd.read_csv(file) # 若CSV中neighbors是字符串格式(如"['a','b']"),需先转成列表: # df['neighbors'] = df['neighbors'].apply(eval) # 展开列表为多行,过滤空值 df_expanded = df.explode('neighbors').dropna(subset=['neighbors']) all_data.append(df_expanded) # 合并所有数据并去重 merged_df = pd.concat(all_data, ignore_index=True).drop_duplicates(subset=['id', 'neighbors']) # 2. 生成邻接矩阵 adjacency_matrix = merged_df.pivot(index='id', columns='neighbors', values='neighbors') # 将存在的配对标记为1,缺失值设为NaN adjacency_matrix = adjacency_matrix.notna().astype(int).replace(0, float('nan'))
代码说明
explode是pandas的向量化操作,比手动循环展开列表效率高几个数量级;drop_duplicates避免重复处理同一id-邻居配对;pivot配合notna()快速完成矩阵转换,完全替代原代码的嵌套循环逻辑。
示例验证
用上述示例数据测试代码,输出结果与目标完全一致:
neighbors a b c d id 11 1.0 NaN 1.0 NaN 12 1.0 1.0 NaN NaN 13 NaN NaN NaN 1.0
内容的提问来源于stack exchange,提问作者Rasmus
相关产品推荐
相关产品推荐

