使用python pandas

时间:2017-12-05 04:51:59

标签: python pandas many-to-many relationship

提前感谢:

我试图在多对多关系表中生成一个组标识符,该表有2列定义父实体和子实体的ID:

以下示例数据框:(父(p)和子(c))

df = pd.DataFrame(np.array([[1,7],[1,3],[1,4],[3,2],[5,1],[6,0]]))
df.columns= ['p', 'c']

表如下所示:

p  c
1  7
1  3
1  4
3  2
5  1
6  0

我试图在一个组中获取所有直接和间接链接的记录。例如:

  • 父记录1是[7,3,4]和
  • 的父级
  • 父记录5是1
  • 的父亲
  • 父记录3是2的父亲,2是1的幼子

所以我想为所有相关记录生成一个ID。如果父记录6与任何记录无关,我会将其移动到另一个组,样本结果如下:

p  c  grp
1  7  A
1  3  A
1  4  A
3  2  A
5  1  A
6  0  B

我目前的思维方式:

对于每条记录,如果它还没有组:

  • 获取所有直接相关的记录ID
  • 然后为每个直接相关的记录ID递归执行相同的功能,找到孩子的所有相关记录,直到他们没有子记录
  • 然后将一个组分配给记录ID组(列表)

我不确定这是否是正确的方法,它似乎是不必要的慢,我必须将链中的所有父记录传递给子记录,以便它不执行同样搜索已搜索的结果。

如果有人能给我一个更好的解决方案,我真的很感激。 :)

2 个答案:

答案 0 :(得分:2)

您可以查看networkx

import networkx as nx

G=nx.from_pandas_dataframe(df, 'c', 'p')
l=list(nx.connected_components(G))
dfmap=pd.DataFrame.from_dict(l)
dfmap.index=['B','A']
dfmap=dfmap.stack()
d=dict(list(zip(dfmap.values.astype(int),dfmap.index.get_level_values(0))))
df['grp']=df.replace(d).p
df
Out[14]: 
   p  c grp
0  1  7   A
1  1  3   A
2  1  4   A
3  3  2   A
4  5  1   A
5  6  0   B

更多信息

import matplotlib.pyplot as plt
nx.draw(G)

enter image description here

答案 1 :(得分:0)

我会发布我的解决方案,因为它更快(对于这个小数据集)并希望有人能提高它的效率。

import netowrkx as nx
import pandas as pd
df = pd.DataFrame(np.array([[1,7],[1,3],[1,4],[3,2],[5,1],[6,0]]))
df.columns= ['p', 'c']

G = nx.from_pandas_dataframe(df, 'p','c')
subgraphs = list(nx.connected_components(G))
grouplist = list('BA')

def defineGrouping(x):
    return grouplist[[n for n,i in enumerate(subgraphs) if x in i][0]]

df['grp'] = df.c.map(defineGrouping)
df

输出:

   p  c grp
0  1  7   A
1  1  3   A
2  1  4   A
3  3  2   A
4  5  1   A
5  6  0   B

时间因为我怀疑Pandas开销是显着的

@ Wen的方法将connected_components转换回pandas dataframe

  

100个循环,最佳3:每循环6.47 ms

这种使用列表理解和枚举的方法:

  

1000个循环,最佳3:每循环1.14毫秒