【问题标题】:Fastest way with parallelization to compute distances between two points with Python code使用 Python 代码计算两点之间距离的最快方法
【发布时间】:2016-06-13 12:37:46
【问题描述】:

我有一个包含数百万行的数据框“数据”。每行都有坐标('x','y'),我想以python可以提供的最有效的方式计算连续坐标对之间的距离。并行化在这里有帮助吗?

我在这里看到了建议使用 cython 的方法。但是,我只想查看 python 解决方案。

这是我的数据的 sn-p

points = 
[(26406, -6869),
 (27679, -221),
 (27679, -221),
 (26416, -6156),
 (26679, -578),
 (26679, -580),
 (27813, -558),
 (26254, -1097),
 (26679, -580),
 (27813, -558),
 (28258, -893),
 (26253, -1098),
 (26678, -581),
 (27811, -558),
 (28259, -893),
 (26252, -1098),
 (27230, -481),
 (26679, -582),
 (27488, -5849),
 (27811, -558),
 (28259, -893),
 (26250, -1099),
 (27228, -481),
 (26679, -582),
 (27488, -5847),
 (28525, -1465),
 (27811, -558),
 (28259, -892)]

我相信我第一个使用 for-loop 的方法肯定可以改进:

    from scipy.spatial import distance
    def comp_dist(points):
        size  =len(points)
        d = 0
        i=1
        for i in range(1,size):
            if i%1000000==0:
                print i
            # print "i-1:", points[i-1]
            # print "i: ", points[i]
            dist = distance.euclidean(points[i-1],points[i])
            d= d+dist
        print d

    distance = comp_dist(points)

提前感谢您的回答。

【问题讨论】:

  • 使用 numpy 会比您当前的解决方案更快,并且比 Cython 更容易实现。不过,它不会为您提供并行化(例如,它可能会针对您的 CPU 进行优化)。
  • 如果你要走多处理路线,你需要将你的大列表分成块,处理它们,然后在最后合并它们
  • 你认为它会提高性能吗?
  • 这取决于数据的大小,并行启动作业是有成本的,但随着数据大小的增加,这会抵消。如果您的任务在几毫秒内完成,那通常是不值得的
  • 我有4900万个坐标

标签: python performance parallel-processing


【解决方案1】:

您说的是 python,但由于您已经在使用 scipy 进行距离计算,所以我认为 numpy 解决方案是可以的。

在我的笔记本电脑上对 2800 万点 numpy 数组使用矢量化单线程操作仅需 1 秒。使用 32 位整数数据类型,该数组占用大约 200MB 内存。

import numpy as np
points = [(26406, -6869), ..., (28259, -892)]
# make test array my repeating the 28-element points list 1M times
np_points = np.array(points*1000000, dtype='int32')
# use two different slices (offset by 1) from resulting array;
# execution of next line takes ~1 second
dists = np.sqrt(np.sum((np_points[0:-2] - np_points[1:-1])**2, axis=1))
print(dists.shape)
(27999998,)

print(dists[:28])
[  6.76878372e+03   0.00000000e+00   6.06789865e+03   5.58419672e+03
   2.00000000e+00   1.13421338e+03   1.64954600e+03   6.69263775e+02
   1.13421338e+03   5.57000898e+02   2.01545280e+03   6.69263775e+02
   1.13323343e+03   5.59400572e+02   2.01744244e+03   1.15636197e+03
   5.60180328e+02   5.32876815e+03   5.30084993e+03   5.59400572e+02
   2.01953386e+03   1.15689585e+03   5.58213221e+02   5.32679134e+03
   4.50303153e+03   1.15431581e+03   5.58802291e+02   6.25764636e+03]

【讨论】:

  • 您可以将其与进程级并行化结合起来,但这不太可能有帮助,因为相对于工作量而言,复制和进程初始化的开销很大。
【解决方案2】:

以下是帮助您入门的简单示例:

from scipy.spatial import distance
from multiprocessing import Pool

processes = 4

# Group data into pairs in order to compute distance
pairs = [(points[i], points[i+1]) for i in range(len(points)-1)]
print pairs

# Split data into chunks
l = [pairs[i:i+processes] for i in xrange(0, len(pairs), processes)]


def worker(lst):
    return [distance.euclidean(i[0], i[1]) for i in lst]

if __name__ == "__main__":
    p = Pool(processes)
    result = p.map(worker, l)
    # Flatten list
    print [item for sublist in result for item in sublist]

对此进行测试:

points =[(random.randint(0,1000), random.randint(0, 1000)) for i in range(1000000)]

8 个进程大约需要 5 秒,1 个进程需要 10 秒。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-26
    • 1970-01-01
    • 2013-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多