我有一个包含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
但是我被困在这里因为我无法过滤掉不需要的行。更重要的是,数据框太大,以至于合并耗尽内存。
所以我有两个问题:有没有办法在不使用合并的情况下完成结果?如果没有,有没有办法过滤掉不需要的行(优先合并之前)?
感谢。
答案 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
三元组。
那就是说,根据你案例的具体情况,这里最大的问题是你会做很多最坏情况下的相似性匹配 - 检查没有任何共同点的值。您可能需要查看一些图表库,例如networkx
或igraph
,以查看图算法是否会对您有所帮助。