首页 > 解决方案 > 过滤 Numpy 数组以获取不包括相等值但符号相反的负值

问题描述

我有

x = np.array([20000, 700, 1000, -5000, -250, 30, -1000, 50, -30, 75, -999])

我想排除这些值-1000-30因为它们前面x有对应的值100030我想得到

y = np.array([-5000, -250, -999])

标签: pythonnumpy

解决方案


有一个快速O(n log n)有效和矢量化的 Numpy 实现

这个想法是在x(with np.unique) 中找到唯一值,并为每个唯一值定位其第一个位置。然后你可以选择if is found before 和v中的值。要查找之前是否找到它,您可以在已排序的唯一值(带有)中执行二分法,以查找当前索引是否大于找到的索引(在唯一值中)。x-vv < 0np.searchsorted

这是生成的代码:

xUnique, xFirstPos = np.unique(x, return_index=True)
xIsNeg = x < 0
xNeg = -x
xNegUniquePos = np.searchsorted(xUnique, xNeg)
xNegIsFound = xUnique[xNegUniquePos] == xNeg
xHasNegBefore = np.logical_and(xNegIsFound, xFirstPos[xNegUniquePos] < np.arange(len(x)))
result = x[np.logical_and(xIsNeg, np.logical_not(xHasNegBefore))]
print(result)

以下是一些示例的结果:

x = np.array([20000, 700, 1000, -5000, -250, 30, -1000, 50, -30, 75, -999])
result = np.array([-5000,  -250,  -999])

x = np.array([-5, 5, -5])
result = np.array([-5])

以下是大小为 100_000 的随机数组的时序(33% 的负值在 -1_000_000 到 2_000_000 范围内):

Mad Physicist's Numpy implementation:         38900.0 ms
Emi OB's implementation:                       1360.0 ms (incorrect so far)
Mad Physicist's pure Python implementation:      40.0 ms
This implementation:                             14.1 ms

到目前为止,这个实现比其他实现快得多。对于这种输入大小,Mad Physicist 的 Numpy 实现占用了几 GiB 的内存,而其他解决方案(包括这个)占用的内存不超过 10 MiB,这毫无价值。


推荐阅读