如何计算列a中每对值之间的列b中的共享值的数量?

时间:2017-03-14 03:59:26

标签: algorithm pandas dataframe graph merge

我有一个包含2列的数据框' la'和' lb'。我想计算每对' la'之间的共享lb值的数量。价值,条件不计算在同一' la'值和不计数一对无序,例如,不计数(1,1),如果计数(1,2)不计数(2,1)。你可以把它想象成在' la'之间建立一个无向的,而不是自我循环的加权图。节点

d = pd.DataFrame([[1, 0], [2, 0], [1, 1], [2, 1]], columns=['la', 'lb'])
d
Out[26]: 
   la  lb
0   1   0
1   2   0
2   1   1
3   2   1

# The final result I want:
   la_x  la_y  count_shared_lb
0     1     2   2
1   ...   ... ...
.
.
.

目前我正在进行合并,然后是groupby和count。

dd= d.merge(d, left_on='lb', right_on='lb')
dd
Out[27]: 
   la_x  lb  la_y
0     1   0     1
1     1   0     2
2     2   0     1
3     2   0     2
4     1   1     1
5     1   1     2
6     2   1     1
7     2   1     2

dd.groupby(['la_x', 'la_y'], sort=False).size().reset_index(name='count_shared_lb')
Out[30]: 
   la_x  la_y  count_shared_lb
0     1     1                2
1     1     2                2
2     2     1                2
3     2     2                2

但是我被困在这里因为我无法过滤掉不需要的行。更重要的是,数据框太大,以至于合并耗尽内存。

所以我有两个问题:有没有办法在不使用合并的情况下完成结果?如果没有,有没有办法过滤掉不需要的行(优先合并之前)?

感谢。

1 个答案:

答案 0 :(得分:1)

对于两个,您可以通过删除具有d唯一值的所有行来提前缩小lb。这个不会解决合并问题,但应该缩小初始占用空间。

counts = d.lb.value_counts()
uniq_lbs = set(counts[counts < 2].index)
d = d[~d.lb.isin(uniq_lbs)]

至于其中一个,最简单的答案就是删除所有行la_x >= la_y,因为这应该涵盖所有冗余计数。也就是说,如果您通过for-loop而不是一个大合并然后连接结果来进行一些较小的合并,那么它可能会更有效率。这应该让您首先跳过两次匹配的东西。

la_vals = sorted(df.la.unique())
d_list = []
for i in range(len(la_vals)-1):
    left_d = d.loc[d.la == la_vals[i], :]
    right_d = d.loc[d.la.isin(la_vals[i:]), :]
    d_list.append(left_d.\
                         merge(right_d, left_on = 'lb', right_on = 'lb').\
                         loc[:, ['la_x', 'la_y']])

final_d = pd.concat(d_list)

你应该能够毫不费力地并行化上述内容,因为d中的任何内容都没有被改变。如果您这样做,请考虑在每个流程中进行计数,然后使用总和汇总所有la_x, la_y, count三元组。

那就是说,根据你案例的具体情况,这里最大的问题是你会做很多最坏情况下的相似性匹配 - 检查没有任何共同点的值。您可能需要查看一些图表库,例如networkxigraph,以查看图算法是否会对您有所帮助。