将坐标分组到彼此的距离内

时间:2017-09-19 14:08:22

标签: python-3.x list pandas nested-loops

我编写的这段代码可以使用,但需要很长时间(约8小时)才能完成执行。

想知道是否可以优化它以更快地执行。

目的是根据彼此的距离对大量物品(x,y,z)进行分组。例如;

我想将它们分组为x中的+ -0.5,y中的+ -0.5和z中的+ -0.5,然后下面数据的输出将为[(0,3),(1),(2,4)...]

        x     y     z
0  1000.1  20.2  93.1
1   647.7  91.7  87.7
2   941.2  44.3  50.6
3  1000.3  20.3  92.9
4   941.6  44.1  50.6
...

我所做的(以及哪些有效)描述如下。

它将data_frame的第一行与第2,第3,第4行比较直到结束,并且对于每一行,如果距离x to x < +-0.5 and y to y < +-0.5 and z to z < +- 0.5然后将索引添加到列表中,group。如果它没有,则它比较下一行直到到达循环结束。

每个循环完成后,匹配(存储在group)中的索引将作为一个集添加到另一个列表groups中,然后从原始列表a中删除,然后比较下一个a[0],依此类推。

groups = []   
group = [] 
data = [(x,y,z),(x,y,z),(etc)] # > 50,000 entries

data_frame = pd.DataFrame(data, columns=['x','y','z'])

a = list(i for i in range(len(data_frame)))

threshold = 0.5

for j in range(len(a) - 1) :
    if len(a) > 0:
        group.append(a[0])
        for ii in range(a[0], len(data_frame) - 1):
            if ((data_frame.loc[a[0],'x'] - data_frame.loc[ii,'x']) < threshold) and ((data_frame.loc[a[0],'y'] - data_frame.loc[ii,'y']) < threshold) and ((data_frame.loc[a[0],'z'] - data_frame.loc[ii,'z']) < threshold):
                group.append(ii)
            else:
                continue
        groups.append(set(group))
        for iii in group:
            if iii in a:
                a.remove(iii)
            else:
                continue
        group = []
    else:
        break

返回类似的东西,例如;

groups = [{0}, {1, 69}, {2, 70}, {3, 67}, {4}, {5}, {6}, {7, 9}, {8}, {10}, {11}, {12}, 13}, {14, 73}, {15}, {16}, {17, 21, 74}, {18, 20}, {19}, {22, 23}]

对这个问题做了很多编辑,因为它不是很清楚。希望现在有意义。

以下是尝试使用更好的逻辑&#O;(NlogN)&#39;哪个更快,但没有返回正确的答案。对x,y,z使用了相同的+ -0.5。

编辑:

test_list = [(i,x,y,z), ... , (i,x,y,z)]

df3 = sorted(test_list,key=lambda x: x[1])

result = []
while df3:
    if len(df3) > 1:    ####added this because was crashing at the end of the loop
        a = df3.pop(0)
        alist=[a[0]]
        while ((abs(a[1] - df3[0][1]) < 0.5) and (abs(a[2] - df3[0][2]) < 0.5) and (abs(a[3] - df3[0][3]) < 0.5)):
            alist.append(df3.pop(0)[0])
            if df3:
                continue
            else:
                break
        result.append(alist)
    else:
        result.append(a[0])
        break

1 个答案:

答案 0 :(得分:1)

由于您要将每个数据点与每个数据点进行比较,因此您的实现的时间复杂度最差为O(N!)。更好的方法是先进行排序。

import random
df = [i for i in range(100)]
random.shuffle(df)
df2 = [(i,x) for i,x in enumerate(df)]
df3 = sorted(df2,key=lambda x: x[1])

df3
[(31, 0), (24, 1), (83, 2)......

假设您现在要将+ 5 / -5的组号分组到一个列表中。然后,您可以根据条件将数字切片到列表中。

result = []
while df3:
    a = df3.pop(0)
    alist=[a[0]]
    while a[1] + 5 >= df3[0][1]:
        alist.append(df3.pop(0)[0])
        if df3:
            continue
        else:
            break
    result.append(alist)

result
[[31, 24, 83, 58, 82, 35], [0, 65, 77, 41, 67, 56].......

排序需要O(NlogN),分组基本上需要线性时间。所以这比N要快得多!