Find closest float in array for all floats in another array
我在根据另一个数组中找到的最近的浮点值"过滤"一个数组时遇到性能问题。
这是一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import numpy as np def random_data(N): # Generate some random data. return np.random.uniform(0., 10., N).tolist() # Data lists. N1 = 1500 list1 = [random_data(N1), random_data(N1), random_data(N1)] list2 = random_data(1000) # Define list1's range. min_1, max_1 = min(list1[2]), max(list1[2]) # This list will contain the"filtered" list1. list4 = [[], [], []] # Go through each element in list2. for elem2 in list2: # If it is located within the list1 range. if min_1 <= elem2 <= max_1: # Find the closest float in sub-list list1[2] to this float # in list2. indx, elem1 = min(enumerate(list1[2]), key=lambda x:abs(x[1]-elem2)) # Store the values in list1 that are associated with the closest float # found above. list4[0].append(list1[0][indx]) list4[1].append(list1[1][indx]) list4[2].append(elem1) |
(注意,
此块按预期工作,但效率极低。我确信答案在于广播和
因为我是在提高这段代码的性能之后,任何解决方案都可以做到(即:我不受一定要使用广播的答案的约束)
添加
作为参考,在不久前我提出的这个类似问题中,快速加权的欧几里得数组中点之间的距离,用户Ali_m使用广播来实现惊人的性能改进。
这个问题并不完全相同(欧几里得距离而不是绝对值,而且这个问题中的距离必须加权),但在我看来这个问题比那个问题更简单。
Ali_m应用于该问题的广播解决方案不能应用于此吗?
添加2
用户2357112给出的答案以及Eelco Hoogendoorn的更正对于我最初定义的代码非常有用。我刚刚意识到我过度简化了它,在我的实际代码中,清单
1 2 3 4 5 6 7 8 | def random_data(N, xi, xf): # Generate some random data. return np.random.uniform(xi, xf, N).tolist() # Data lists. N1 = 1500 list1 = [random_data(N1, 13., 20.), random_data(N1, -1., 4.), random_data(N1, 2., 7.)] list2 = random_data(1000, 0., 10.) |
号
现在,
是否可以修改答案以考虑这种可能性?我很抱歉更改了这样的原始代码,它真的被我偷走了。
在这里,kd树真的是太过分了,你需要做的就是对数组进行排序,然后使用二进制搜索在排序后的数组中找到最接近的值。前一段时间我写了一个关于如何使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import numpy as np def find_closest(A, target): #A must be sorted idx = A.searchsorted(target) idx = np.clip(idx, 1, len(A)-1) left = A[idx-1] right = A[idx] idx -= target - left < right - target return idx def random_data(shape): # Generate some random data. return np.random.uniform(0., 10., shape) def main(data, target): order = data[2, :].argsort() key = data[2, order] target = target[(target >= key[0]) & (target <= key[-1])] closest = find_closest(key, target) return data[:, order[closest]] N1 = 1500 array1 = random_data((3, N1)) array2 = random_data(1000) array2[[10, 20]] = [-1., 100] array4 = main(array1, array2) |
如果你有坐骨神经痛,一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import numpy import scipy.spatial array1 = numpy.array(list1) array2 = numpy.array(list2) # A tree optimized for nearest-neighbor lookup tree = scipy.spatial.cKDTree(array1[2, ..., numpy.newaxis]) # The distances from the elements of array2 to their nearest neighbors in # array1, and the indices of those neighbors. distances, indices = tree.query(array2[..., numpy.newaxis]) array4 = array1[:, indices] |
K-D树是为多维数据设计的,所以这可能不是最快的解决方案,但与您拥有的相比,它应该是相当快的。k-d树期望以点的二维数组的形式输入,其中
如果需要拒绝来自
1 2 3 4 5 | lowbound = array1[2].min() highbound = array1[2].max() querypoints = array2[(array2 >= lowbound) & (array2 <= highbound)] distances, indices = tree.query(querypoints[..., numpy.newaxis]) |
号