Python NumPy:np.lexsort,具有模糊/容忍比较
我有一个三维的Python NumPy:np.lexsort,具有模糊/容忍比较,python,sorting,numpy,floating-point,Python,Sorting,Numpy,Floating Point,我有一个三维的N点集合。它们存储为np.数组,形状为(N,3)。所有点都是不同的,任意两点之间的最小距离为~1e-5。我正在寻找一种方法,以获得在这些点上迭代的顺序,该顺序既独立于它们在np.array中的当前顺序,又对单个组件的小扰动具有鲁棒性 满足第一个需求的最简单方法是使用np.lexsortwith np.lexsort(my_array.T) 但是,在健壮性部门,这是失败的: In [6]: my_array = np.array([[-0.5, 0, 2**0.5], [0.5,
N
点集合。它们存储为np.数组
,形状为(N,3)
。所有点都是不同的,任意两点之间的最小距离为~1e-5
。我正在寻找一种方法,以获得在这些点上迭代的顺序,该顺序既独立于它们在np.array
中的当前顺序,又对单个组件的小扰动具有鲁棒性
满足第一个需求的最简单方法是使用np.lexsort
with
np.lexsort(my_array.T)
但是,在健壮性部门,这是失败的:
In [6]: my_array = np.array([[-0.5, 0, 2**0.5], [0.5, 0, 2**0.5 - 1e-15]])
In [7]: my_array[np.lexsort(my_array.T)]
Out[7]:
array([[ 0.5 , 0. , 1.41421356],
[-0.5 , 0. , 1.41421356]])
我们可以看到,在这种情况下,排序对扰动非常敏感。因此,我正在寻找np.lexsort
的模糊变量,如果一个轴上的两个值在epsilon
的公差范围内,该变量将移动到下一个轴上。(或允许我获得订单的任何替代机制。)
由于我的应用程序有数百万个这样的集合,所有这些集合都需要排序,因此性能是一个值得关注的问题(这就是为什么我没有在没有看到是否有更好的方法之前盲目地尝试使用我自己的容错np.lexsort)。我最终的解决方案是:
def fuzzysort(arr, idx, dim=0, tol=1e-6):
# Extract our dimension and argsort
arrd = arr[dim]
srtdidx = sorted(idx, key=arrd.__getitem__)
i, ix = 0, srtdidx[0]
for j, jx in enumerate(srtdidx[1:], start=1):
if arrd[jx] - arrd[ix] >= tol:
if j - i > 1:
srtdidx[i:j] = fuzzysort(arr, srtdidx[i:j], dim + 1, tol)
i, ix = j, jx
if i != j:
srtdidx[i:] = fuzzysort(arr, srtdidx[i:], dim + 1, tol)
return srtdidx
我注意到,对于上面描述的问题,这有点过度设计。与np.lexsort
一样,数组必须以转置形式传递。idx
参数允许控制所考虑的索引(允许对元素进行粗略屏蔽)。否则列表(xrange(0,N))
就可以了
表演不是很好。然而,这主要是NumPy标量类型表现不好的结果。事先在数组上调用
tolist()
会在某种程度上改善这种情况。我也遇到了同样的问题,只是在2D中遇到了一个x,y坐标列表,我需要用公差排序。我最终基于numpy.lexsort
编写了这个解决方案:
def tolerance_sort(array, tolerance):
array_sorted = np.copy(array[np.lexsort((array[:, 0], array[:, 1]))])
sort_range = [0]
for i in range(array.shape[0] - 1):
if array_sorted[i + 1, 1] - array_sorted[i, 1] <= tolerance:
sort_range.append(i + 1)
continue
else:
sub_arr = np.take(array_sorted, sort_range, axis=0)
sub_arr_ord = np.copy(
sub_arr[np.lexsort((sub_arr[:, 1], sub_arr[:, 0]))])
array_sorted[slice(sort_range[0], sort_range[-1] +
1)] = sub_arr_ord
sort_range = [i + 1]
return array_sorted
这(公差=0.1
):
我没有时间进行泛化,所以这只适用于2D,目前您无法控制排序顺序(先按第二列,然后按第一列)。我需要同样的方法,先按实部,然后按虚部对复数进行排序,但实部排序应该考虑数字相等,如果它们在一定范围内。你找到解决办法了吗?我之前所做的是先使用lexsort对它们进行近似排序,然后使用一种不太理想的冒泡排序算法进行迭代,将顺序错误的值分组。
array([[ 11. , 4. ],
[ 1. , 0. ],
[ 7. , 10. ],
[ 2. , 9. ],
[ 9. , 9. ],
[ 5. , 4. ],
[ 1. , 2. ],
[ 1. , 0. ],
[ 0. , 0.1 ],
[ 2. , 0.06]])
array([[ 0. , 0.1 ],
[ 1. , 0. ],
[ 1. , 0. ],
[ 2. , 0.06],
[ 1. , 2. ],
[ 5. , 4. ],
[ 11. , 4. ],
[ 2. , 9. ],
[ 9. , 9. ],
[ 7. , 10. ]])