Python - 优化 N 中的 2 与 N 非常大的组合

Posted

技术标签:

【中文标题】Python - 优化 N 中的 2 与 N 非常大的组合【英文标题】:Python - Optimizing combination of 2 among N with N very large 【发布时间】:2019-06-14 07:11:39 【问题描述】:

我试图找到满足特定条件的元素对。更准确地说,我想在 50,000 个元素中形成 2 个(无序)元素的组合,以便遵守某个条件。

我的数据集包含 50,000 个具有唯一标识符和一些可观察值(位置和截止点)的元素。我想形成 2 个元素的无序对,使得两个成对元素之间的距离低于给定的截止值。

到目前为止,我的脚本如下。

# Load the dataset (I have a custom function for it called loadFile)
df = loadFile(path_input,filename_input)

# Reset the index because I want to use the column "index" from 0 to 49,999
df = df.reset_index(drop=False)

# Initiate the list of pairs & get the number of elements
pairs = list()
nb_rows = df.shape[0]

# Loop over all the rows of my dataframe
for ind_x, x in df.iterrows():
    # Just print to know where we stand from 1 to 50,000
    print(" out of ".format(ind_x+1,nb_rows))
    # Loop over all the rows of my dataframe
    for ind_y, y in df.iterrows():
        # We only consider the y-row if it was not covered yet by the previous pairs
        # I also don't want to cover the case where both elements are equal
        if ind_x<ind_y:
            # Here is a custom condition (a simple function) returning a boolean
            if distance(x["location"],y["location"])<x["cutoff"]:
                pairs.append((x["id"],y["id"]))

实际上,如果我的自定义条件始终得到遵守,我的脚本可以遍历所有 50,000 * 49,999 / 2 ~ 1 2.5 亿 个可能的对..

对于一个“ind_x”元素,当前循环运行大约需要 5 秒,这使得运行脚本需要 50,000 * 5 / (60²) = 69 小时(很多)。

有什么方法可以加快我的脚本,无论是循环本身还是修改我的方法以节省时间?

提前谢谢你,

M

【问题讨论】:

iterrows() 一般不推荐使用。 您好约瑟夫,感谢您的回答。你建议我改用 .itertuples 吗? medium.com/@rtjeannier/pandas-101-cont-9d061cb73bfc看看这篇文章。 如果能够将两帧完全合并,那么判断是否满足条件就很简单了,而且速度也快很多。但是,仅包含与您的循环匹配的行(排除先前匹配的匹配项)的逻辑可能难以实现。至少,这将其简化为最多 50,000 个组的单个循环,我猜它可以在没有它的情况下完成。 【参考方案1】:

这只是寻找邻域集的经典问题。只要你的距离是欧几里得,有很多专门的包用快速的方法来解决它,但一个不错的选择是利用 scipy 的cKDTree:

from scipy.spatial import cKDTree

def close_point_pairs(X, max_d):
    # create the tree from the data points
    tree = cKDTree(X)

    # find all pairs of points 
    pairs = tree.query_ball_tree(tree,max_d)

    # pair indices
    return np.array([(x, pt) for x, ptlist in enumerate(pairs) for pt in ptlist if pt>x])

这将创建一个包含所有索引对的 numpy 数组。它非常快,大部分运行时间都被最后一个对扩展所消耗:

df = pd.DataFrame(500*np.random.random(size=10**4), columns=['location'])
%timeit close_point_pairs(df['location'].values[:,np.newaxis], max_d=1.0)
530 ms ± 123 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

注意我必须添加 np.newaxis 因为这些点只是一维的,不清楚你的位置点是什么,但如果它们的维度更高,你应该删除它。

如果您需要原始 DataFrame 中的唯一 id,您可以直接索引到它或创建一个翻译字典。

【讨论】:

非常感谢!我会仔细研究的!

以上是关于Python - 优化 N 中的 2 与 N 非常大的组合的主要内容,如果未能解决你的问题,请参考以下文章

使用缓存方式优化递归函数与lru_cache

Python开启尾递归优化!

矩阵快速幂优化线性递推

删除与Python列表中的条件匹配的前N个项

挖掘算法中的数据结构:O(n^2)排序算法之 选择插入冒泡希尔排序 及 优化

Python进阶内容--- 函数式编程