簡體   English   中英

加快python中的代碼塊

[英]Speeding up block of code in python

我發現了兩個潛在的原因,原因是給定的點是10000個size-2列表,因此以下代碼段的性能非常差。

  1. “添加”以給定鍵添加新值
  2. 鄰居地圖字典。

     def calculate_distance(point1, point2): a = (point1[0], point1[1]) b = (point2[0], point2[1]) return distance.euclidean(a, b) def get_eps_neighbours(points, eps): neighbours = {} index = 0 for p in points: for q in points: if(calculate_distance(p, q) <= eps): if index in neighbours: neighbours[index].append(q) else: neighbours[index] = q index = index + 1 return {'neighbours': neighbours} 

關於如何提高代碼效率的任何建議?

這是一個平凡的並行問題的例子。

我的建議:

  • 使用numpy
  • 創建2個點^點矩陣(2D數組),一個用於x另一個用於y
  • 使用numpy的數組算法

例:

In [52]: points = [(1,1), (2,2), (3,3), (4,4)]  # super-simple data

In [54]: Xb = numpy.repeat(numpy.array(points)[:,0], 4).reshape(4, 4)

In [60]: Xb
Out[60]: 
array([[1, 1, 1, 1],
       [2, 2, 2, 2],
       [3, 3, 3, 3],
       [4, 4, 4, 4]])

In [61]: Xa = numpy.tile(numpy.array(points)[:,0], 4).reshape(4, 4)

In [62]: Xa
Out[62]: 
array([[1, 2, 3, 4],
       [1, 2, 3, 4],
       [1, 2, 3, 4],
       [1, 2, 3, 4]])

# Yb = numpy.repeat(numpy.array(points)[:,1], 4).reshape(4, 4)
# Ya = numpy.tile(numpy.array(points)[:,1], 4).reshape(4, 4)

In [65]: D = ((Xa - Xb) ** 2 + (Ya - Yb) ** 2) ** 0.5

In [66]: D
Out[66]: 
array([[ 0.        ,  1.41421356,  2.82842712,  4.24264069],
       [ 1.41421356,  0.        ,  1.41421356,  2.82842712],
       [ 2.82842712,  1.41421356,  0.        ,  1.41421356],
       [ 4.24264069,  2.82842712,  1.41421356,  0.        ]])

In [71]: D < 2
Out[71]: 
array([[ True,  True, False, False],
       [ True,  True,  True, False],
       [False,  True,  True,  True],
       [False, False,  True,  True]], dtype=bool)

# Assuming you want only one copy from each pair (a,b), (b,a)
In [73]: triangle = numpy.tri(4, 4, -1, bool)

In [74]: triangle
Out[74]: 
array([[False, False, False, False],
       [ True, False, False, False],
       [ True,  True, False, False],
       [ True,  True,  True, False]], dtype=bool)

In [76]: neighbours = (D < 2) * triangle  # multiplication for "logical and"
Out[76]: 
array([[False, False, False, False],
       [ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False]], dtype=bool)

# Neighbours' x and y coordinates are available so:
In [107]: numpy.compress(neighbours.flatten(), Xa.flatten())
Out[107]: array([1, 2, 3])

# Indices to elements in original `points` list like this:
Indexb = numpy.repeat(numpy.arange(4), 4).reshape(4, 4)
Indexa = numpy.tile(numpy.arange(4), 4).reshape(4, 4)
numpy.transpose([numpy.compress(neighbours.flatten(), Indexa.flatten()),
                 numpy.compress(neighbours.flatten(), Indexb.flatten())])
array([[0, 1],
       [1, 2],
       [2, 3]])

有了算法的總體思路,我認為您可以通過先刪除(或復制到另一個列表)僅2*abs(px - qx) <= eps (重復y)的元素來減少經過歐幾里得距離測試的點的列表,這比計算所有點的歐幾里得要快得多。 如果eps小,那將起作用。

我不知道這是否可以加快您的代碼的速度,但是計數循環的Python方法是這樣的:

for i, p in enumerate(points):

另外-我不確定我是否每次都能理解整個字典(map)鍵的邏輯。 這段代碼看起來並不像在做有用的事情

neighBourMap[index] = q

這會將鍵值對q的鍵值對添加到字典中。 您是否嘗試過僅使用列表,即

neighBourMap = []

所有其他答案都是正確的,但是它們不會給您帶來巨大的提速。 使用numpy數組可以使您加速,並行化可以使您加速。 但是,如果您擁有一百萬個點,並且仍然使用當前的算法(進行n ^ 2距離計算),那么加速將不夠。 (100萬)^ 2是通往許多目標的方法。 如果您使用numpy?

您應該切換算法。 您應該將點存儲在kd樹中。 這樣,您可以將搜索集中在幾個鄰近的候選對象上。 除了遍歷所有點q ,您可以簡單地使用|qx - px| < eps and |qy - py| < eps遍歷所有點q |qx - px| < eps and |qy - py| < eps |qx - px| < eps and |qy - py| < eps |qx - px| < eps and |qy - py| < eps 如果您的eps很小,並且每個點只有幾個鄰居,那么這將使您的速度大大提高。

這是一份pdf文件,其中描述了該算法如何查找特定范圍內的所有點: http : //www.cse.unr.edu/~bebis/CS302/Handouts/kdtree.pdf

您希望所有點相互組合。 您可以使用itertools.combinations

由於我們僅在進行所需的組合,因此無需繼續查找要附加的字典索引。 我們可以將點及其鄰居列表放在一起。

list使用defaultdict意味着我們不必在第一次查找點時手動創建list

另外,您實際上並不需要歐幾里得距離的值,只想知道它是否小於其他值。 因此,比較平方將為您提供相同的結果。

要將point用作字典的鍵,它必須是不可變的,因此我們將其轉換為元組:

def distance_squared(a, b):
    diff = complex(*a) - complex(*b)
    return diff.real ** 2 + diff.imag ** 2

from itertools import combinations
from collections import defaultdict

neighbours = defaultdict(list)
eps_squared = eps ** 2

point_neighbours = ((point, neighbours[tuple(point)]) for point in points)

for (p, p_neighbours), (q, _) in combinations(point_neighbours , r=2):
    if distance_squared(p, q) <= eps_squared:
        p_neighbours.append(q)

一件事情你可以取代

index in neighBourMap.keys()):`

只是

index in neighBourMap

由於不需要創建字典鍵的副本,因此運行速度更快。

更好的是,使用defaultdict(list)可以避免在追加到列表值之前檢查鍵的需求。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM