从电子表格以 Python 方式创建邻接矩阵
Posted
技术标签:
【中文标题】从电子表格以 Python 方式创建邻接矩阵【英文标题】:Pythonically create adjacency matrix from spreadsheet 【发布时间】:2021-08-24 19:56:03 【问题描述】:我有一个电子表格,其中列出了某个特定人员报告的在多个项目中与之合作的人员名单。如果我将它作为数据框导入 pandas,它将如下所示:
1 2
Jane ['Fred', 'Joe'] ['Joe', 'Fred', 'Bob']
Fred ['Alex'] ['Jane']
Terry NaN ['Bob']
Bob ['Joe'] ['Jane', 'Terry']
Alex ['Fred'] NaN
Joe ['Jane'] ['Jane']
我想创建一个如下所示的邻接矩阵:
Jane Fred Terry Bob Alex Joe
Jane 0 2 0 1 0 2
Fred 1 0 0 0 1 0
Terry 0 0 0 1 0 0
Bob 1 0 1 0 0 1
Alex 0 1 0 0 0 0
Joe 2 0 0 0 0 0
这个矩阵通常不会是对称的,因为与人们的报告不一致。我一直在通过循环遍历数据框并相应地递增矩阵元素来创建邻接矩阵。显然,不推荐循环遍历数据帧并且效率低下,那么有没有人建议他如何以更 Python 的方式完成?
【问题讨论】:
只是检查一下,单元格的内容是list
?你能用type(df.iloc[0,0])
验证吗
好问题,当我导入数据时,它实际上是以 '[Name1, Name2, ...]' 形式的字符串出现的,但我应用了一个 string2list() 函数来打开将所有单元格的内容放入列表中。但是,简而言之,答案是肯定的,每个单元格的类型都是list
(除非是np.NaN
)。顺便说一句,我实际上没有名字,而是整数 ID 号(名字已经匿名)所以每个单元格的内容实际上是一个整数列表。
【参考方案1】:
这是我曾经使用过的数据样本。
df = pd.DataFrame(
'Name': ['Jane', 'Fred', 'Terry', 'Bob', 'Alex', 'Joe'],
'1':[['Fred', 'Joe'], ['Alex'], np.nan,['Joe'], ['Fred'], ['Jane']],
'2': [['Joe', 'Fred', 'Bob'], ['Jane'], ['Bob'], ['Jane', 'Terry'], np.nan, ['Jane']]
)
df.head()
Name 1 2
0 Jane [Fred, Joe] [Joe, Fred, Bob]
1 Fred [Alex] [Jane]
2 Terry NaN [Bob]
3 Bob [Joe] [Jane, Terry]
4 Alex [Fred] NaN
我通过三个简单的步骤使用 pandas 创建了邻接矩阵。
首先,我将数据融合为仅用于不同名称之间的所有连接的一列,并删除了变量列。
dff = df.melt(id_vars=['Name']).drop('variable', axis=1)
Name value
0 Jane [Fred, Joe]
1 Fred [Alex]
2 Terry NaN
3 Bob [Joe]
4 Alex [Fred]
5 Joe [Jane]
6 Jane [Joe, Fred, Bob]
7 Fred [Jane]
8 Terry [Bob]
9 Bob [Jane, Terry]
10 Alex NaN
11 Joe [Jane]
其次,我使用了explode方法将行分解为单独的行。
dff = dff.explode('value')
Name value
0 Jane Fred
0 Jane Joe
1 Fred Alex
2 Terry NaN
3 Bob Joe
4 Alex Fred
5 Joe Jane
6 Jane Joe
6 Jane Fred
6 Jane Bob
7 Fred Jane
8 Terry Bob
9 Bob Jane
9 Bob Terry
10 Alex NaN
11 Joe Jane
最后,为了创建邻接矩阵,我在 pandas 中使用了交叉表,它只计算指定的两列中的出现次数。
pd.crosstab(dff['Name'], dff['value'])
value Alex Bob Fred Jane Joe Terry
Name
Alex 0 0 1 0 0 0
Bob 0 0 0 1 1 1
Fred 1 0 0 1 0 0
Jane 0 1 2 0 2 0
Joe 0 0 0 2 0 0
Terry 0 1 0 0 0 0
【讨论】:
这太棒了,正是我想要的。谢谢!【参考方案2】:这是一种方法:
import pandas as pd
import ast
data = ''' 1 2
Jane ['Fred', 'Joe'] ['Joe', 'Fred', 'Bob']
Fred ['Alex'] ['Jane']
Terry NaN ['Bob']
Bob ['Joe'] ['Jane', 'Terry']
Alex ['Fred'] NaN
Joe ['Jane'] ['Jane']'''
df = pd.read_csv(io.StringIO(data), sep='\s\s+', engine='python').fillna('[]').applymap(ast.literal_eval) #if your columns are already lists rather than string representations, use .fillna([]) and skip the applymap
df['all'] = df['1']+df['2'] #merge lists of columns 1 and 2
df_edges = df[['all']].explode('all').reset_index() #create new df by exploding the combined list
df_edges = df_edges.groupby(['index', 'all'])['all'].count().reset_index(name="count") #groupby and count the pairs
df_edges.pivot(index='index', columns='all', values='count').fillna(0) #create adjacency matrix with pivot
输出:
index | Alex | Bob | Fred | Jane | Joe | Terry |
---|---|---|---|---|---|---|
Alex | 0 | 0 | 1 | 0 | 0 | 0 |
Bob | 0 | 0 | 0 | 1 | 1 | 1 |
Fred | 1 | 0 | 0 | 1 | 0 | 0 |
Jane | 0 | 1 | 2 | 0 | 2 | 0 |
Joe | 0 | 0 | 0 | 2 | 0 | 0 |
Terry | 0 | 1 | 0 | 0 | 0 | 0 |
【讨论】:
以上是关于从电子表格以 Python 方式创建邻接矩阵的主要内容,如果未能解决你的问题,请参考以下文章
数据结构与算法图 ( 图的存储形式 | 图的基本概念 | 图的表示方式 | 邻接矩阵 | 邻接表 | 图的创建 | 代码示例 )