将非方形邻接矩阵导入 Networkx python
Importing non-square adjacency matrix into Networkx python
我在下面的 pandas 数据框表单中有一些数据,其中列代表离散的技能,行代表离散的工作。仅当工作需要技能时才出现 1,否则出现 0。
skill_1, skill_2,
job_1 1, 0,
job_2 0, 0,
job_3 1, 1,
我想创建一个图表来可视化工作和技能之间的这种关系,使用 networkx。我尝试了两种方法,一种是在数据帧上,它本身是 nx.from_pandas_adjacency
和 nx.from_numpy_matrix
。后一种方法应用于数据框的 numpy 表示,其中删除了列名和行名。
在任何一种情况下,都会出现错误,因为这是一个 non_square 矩阵。这是有道理的,因为 networkx 可能将列和行解释为同一组节点。但是,列和节点在这里代表截然不同的事物。两个工作通过他们共享的技能联系起来,两个技能通过他们共享的工作联系起来,但是任何两个技能或任何两个工作之间没有直接的优势。
鉴于我的行和列是不同的节点集,我如何将我的数据导入 networkx?
一个选项是生成缺失的行和列
(我对实现此目的的矢量化方法感到好奇,所以我询问了 ,其中提供了提供此类方法的答案。)
df = pd.DataFrame({'skill_1': {'job_1': 1, 'job_2': 0, 'job_3': 1},
'skill_2': {'job_1': 0, 'job_2': 0, 'job_3': 1}})
edges = df.columns
for i in df.index:
df[i] = [0 for _ in range(len(df.index))]
for e in edges:
df = df.append(pd.Series({c:0 for c in df.columns},name=e))
这给了我们:
>>> df
skill_1 skill_2 job_1 job_2 job_3
job_1 1 0 0 0 0
job_2 0 0 0 0 0
job_3 1 1 0 0 0
skill_1 0 0 0 0 0
skill_2 0 0 0 0 0
然后我们可以使用 nx.from_pandas_adjacency
读入 networkx(假设您想要一个有向图)
G = nx.from_pandas_adjacency(df, create_using=nx.DiGraph)
或者,我们可以使用 df.stack()
df = pd.DataFrame({'skill_1': {'job_1': 1, 'job_2': 0, 'job_3': 1},
'skill_2': {'job_1': 0, 'job_2': 0, 'job_3': 1}})
G = nx.DiGraph()
for x,y in df.stack().reset_index().iterrows():
G.add_node(y['level_0'])
G.add_node(y['level_1'])
if y[0]:
G.add_edge(y['level_0'], y['level_1'])
你有一个bipartite graph. Networkx can create this network from your original (bi)adjacency matrix using nx.algorithms.bipartite.matrix.from_biadjacency_matrix
正如 ComplexGates 所提到的,这里有一个双邻接矩阵。我看到您添加了一个解决方案,您在其中用零填充矩阵的其余部分以使其成为正方形。但是,我怀疑您真正想要的是如何将双邻接矩阵转换为(方形)邻接矩阵,这与发布的解决方案不同。
对于 m 行 n 列的双邻接矩阵 A,您可以将其转换为大小为 (m+n)x(m+n) 的邻接矩阵,如下所示:
┏ ┓
┃0_nxn A^T ┃
┃A_mxn 0_mxm┃
┗ ┛
也就是说,把A放在(m+n)x(m+n)矩阵的左下角,把A的转置放在右上角,剩下的space用零。
在代码中,如果 A 是一个 2D Numpy 数组,您可以这样做:
def bipartite_to_adjacency(A):
m, n = A.shape
Z_mm = np.zeros((m,m), dtype=int)
Z_nn = np.zeros((n,n), dtype=int)
top_partition = np.concatenate((Z_nn,np.transpose(A)), axis=1)
bottom_partition = np.concatenate((A,Z_mm), axis=1)
return np.concatenate((top_partition, bottom_partition))
我在下面的 pandas 数据框表单中有一些数据,其中列代表离散的技能,行代表离散的工作。仅当工作需要技能时才出现 1,否则出现 0。
skill_1, skill_2,
job_1 1, 0,
job_2 0, 0,
job_3 1, 1,
我想创建一个图表来可视化工作和技能之间的这种关系,使用 networkx。我尝试了两种方法,一种是在数据帧上,它本身是 nx.from_pandas_adjacency
和 nx.from_numpy_matrix
。后一种方法应用于数据框的 numpy 表示,其中删除了列名和行名。
在任何一种情况下,都会出现错误,因为这是一个 non_square 矩阵。这是有道理的,因为 networkx 可能将列和行解释为同一组节点。但是,列和节点在这里代表截然不同的事物。两个工作通过他们共享的技能联系起来,两个技能通过他们共享的工作联系起来,但是任何两个技能或任何两个工作之间没有直接的优势。
鉴于我的行和列是不同的节点集,我如何将我的数据导入 networkx?
一个选项是生成缺失的行和列
(我对实现此目的的矢量化方法感到好奇,所以我询问了
df = pd.DataFrame({'skill_1': {'job_1': 1, 'job_2': 0, 'job_3': 1},
'skill_2': {'job_1': 0, 'job_2': 0, 'job_3': 1}})
edges = df.columns
for i in df.index:
df[i] = [0 for _ in range(len(df.index))]
for e in edges:
df = df.append(pd.Series({c:0 for c in df.columns},name=e))
这给了我们:
>>> df
skill_1 skill_2 job_1 job_2 job_3
job_1 1 0 0 0 0
job_2 0 0 0 0 0
job_3 1 1 0 0 0
skill_1 0 0 0 0 0
skill_2 0 0 0 0 0
然后我们可以使用 nx.from_pandas_adjacency
读入 networkx(假设您想要一个有向图)
G = nx.from_pandas_adjacency(df, create_using=nx.DiGraph)
或者,我们可以使用 df.stack()
df = pd.DataFrame({'skill_1': {'job_1': 1, 'job_2': 0, 'job_3': 1},
'skill_2': {'job_1': 0, 'job_2': 0, 'job_3': 1}})
G = nx.DiGraph()
for x,y in df.stack().reset_index().iterrows():
G.add_node(y['level_0'])
G.add_node(y['level_1'])
if y[0]:
G.add_edge(y['level_0'], y['level_1'])
你有一个bipartite graph. Networkx can create this network from your original (bi)adjacency matrix using nx.algorithms.bipartite.matrix.from_biadjacency_matrix
正如 ComplexGates 所提到的,这里有一个双邻接矩阵。我看到您添加了一个解决方案,您在其中用零填充矩阵的其余部分以使其成为正方形。但是,我怀疑您真正想要的是如何将双邻接矩阵转换为(方形)邻接矩阵,这与发布的解决方案不同。
对于 m 行 n 列的双邻接矩阵 A,您可以将其转换为大小为 (m+n)x(m+n) 的邻接矩阵,如下所示:
┏ ┓
┃0_nxn A^T ┃
┃A_mxn 0_mxm┃
┗ ┛
也就是说,把A放在(m+n)x(m+n)矩阵的左下角,把A的转置放在右上角,剩下的space用零。
在代码中,如果 A 是一个 2D Numpy 数组,您可以这样做:
def bipartite_to_adjacency(A):
m, n = A.shape
Z_mm = np.zeros((m,m), dtype=int)
Z_nn = np.zeros((n,n), dtype=int)
top_partition = np.concatenate((Z_nn,np.transpose(A)), axis=1)
bottom_partition = np.concatenate((A,Z_mm), axis=1)
return np.concatenate((top_partition, bottom_partition))