【问题标题】:Making Loop-Finding Faster: Numpy Equivalent of Pandas Merge?使循环查找更快:Pandas 合并的 Numpy 等价物?
【发布时间】: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 函数,它们都没有我这里的速度那么快。

我见过this postthis one;其中一些功能是否可行?

【问题讨论】:

标签: python-3.x pandas numpy duplicates graph-theory


【解决方案1】:

你可以试试:

import pandas as pd
import networkx as nx

df = pd.DataFrame(columns=['parent', 'child'])
df.loc[0] = (0, 1)
df.loc[1] = (1, 2)
df.loc[2] = (2, 0)


dg = nx.from_pandas_edgelist(df, source='parent', target='child', create_using=nx.DiGraph)
res = list(nx.simple_cycles(dg))
print(res)

输出

[[0, 1, 2]]

来自simple_cycles上的文档:

找出有向图的简单循环(基本回路)。

一个简单的循环或基本电路是一条没有节点的闭合路径 出现两次。两个基本电路是不同的,如果它们不是 相互循环排列。

在上面的文档链接中,有一些可能感兴趣的其他算法的链接。

【讨论】:

  • 我认为这会奏效,但我需要让我的整体结构更高效,例如只创建一次有向图,并从中添加或删除边,而不是重新创建整个每次的事情。我会及时通知你。
  • 我的循环速度比我实施循环查找之前慢了一点,正如您所料,但这个解决方案,结合我上面提到的东西,是一个可以接受的速度。非常感谢!
猜你喜欢
  • 2018-01-27
  • 1970-01-01
  • 1970-01-01
  • 2017-01-15
  • 1970-01-01
  • 2020-07-21
  • 2020-04-09
  • 1970-01-01
  • 2016-02-26
相关资源
最近更新 更多