【发布时间】:2021-03-25 13:39:06
【问题描述】:
我从有向图中的父/子(边)关系列表开始,如下所示:
import numpy as np
import pandas as pd
df = pd.DataFrame(columns=['parent', 'child'])
df.loc[0] = (0, 1)
df.loc[1] = (1, 2)
df.loc[2] = (2, 0)
您可以立即看到我们有循环0 --> 1 --> 2 --> 0。我希望能够在我拥有的数据框中检测到这些循环。到目前为止,我的策略(在我更大的数据集上有效但速度太慢)是利用 pandas 合并功能:
def find_loops(link_df: pd.DataFrame) -> dict:
link_df.columns = ['0', '1']
# Max number of iterations - don't expect to need this many.
num_appts = len(set(link_df['0']) | set(link_df['1']))
new_df = pd.DataFrame(link_df)
for i in range(num_appts):
new_df = new_df.merge(link_df, left_on=str(i+1), right_on='0', how='inner')
new_df.drop(columns='0_y', inplace=True)
new_df.columns = [str(j) for j in range(i+3)]
这给了我,在每次循环迭代中,new_df.values 中的数组包含长度增加的路径 (i+3)。如果路径结束并且没有循环,那么merge 函数会自动删除该行,这非常好。为了检测循环,我沿着new_df.values 的行查找重复值,如下所示:
paths = new_df.values.astype(np.int32)
is_loop = pd.Series(paths[:, 0] == paths[:, 1])
width = i + 3
for j in range(width - 1):
for k in range(j+1, width):
is_loop = is_loop | (paths[:, j] == paths[:, k])
find_loops(df)
我需要这段代码运行得更快。有任何想法吗?我的一个想法是尝试在 numpy 中执行 pandas merge 函数,但我不知道哪个函数甚至可以做到这一点。
我已经尝试过duplicated 函数、Counter 对象和np.unique 函数,它们都没有我这里的速度那么快。
【问题讨论】:
-
你可能想要的是使用networkx,特别是networkx.org/documentation/stable/reference/algorithms/…
-
@DaniMesejo 非常好!我去看看。
标签: python-3.x pandas numpy duplicates graph-theory