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

时间:2019-01-20 20:39:52

标签: python-3.x pandas performance combinations large-data

我正在尝试寻找满足一定条件的成对元素。更准确地说,我要在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 250百万个可能的对。.

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

是否可以通过循环本身或修改我的方法来节省时间来加快脚本运行速度?

先谢谢您

M

1 个答案:

答案 0 :(得分:2)

这只是查找邻域集的经典问题。只要您的距离是欧几里得,有很多专门的软件包可以快速解决它,但是一个不错的选择是利用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,因为这些点仅为1D,尚不清楚您的位置点是什么,但是如果它们的尺寸较大,则应将其删除。

如果您需要原始DataFrame中的唯一ID,则可以将其索引回索引或创建翻译字典。