有没有一种快速方法可以将numpy数组中的一个元素与该数组中其余元素进行比较?

时间:2013-03-11 14:56:35

标签: python arrays numpy

我有一个数组,我想看看该数组中的任何元素是否大于或等于该数组中的任何其他元素。我可以做两个for循环,但我的数组长度为10,000或更大,因此创建了一个非常慢的程序。无论如何,我可以更快地做到这一点?

[编辑]我只需要它来查看它是否大于或等于我正在查看的元素之后的元素,如果是,我需要知道它的索引。

[编辑] 我将更清楚地重新解释我的问题,因为当前的解决方案不能满足我的需求。首先,这里有一些代码

x=linspace(-10, 10, 10000)
t=linspace(0,5,10000)

u=np.exp(-x**2)

k=u*t+x

所以我采用一个x数组,通过将其置于高斯中获得高度,然后基于该高度,即x值通过空间传播的速度,我用k找到。我的问题是,我需要找到何时高斯变为双值函数(或换句话说,当发生冲击时)。如果我做argmax解决方案,我总是得到k中的最后一个值,因为它非常接近于零,我需要在我的函数中给出一个double值的元素之后的第一个值。

[编辑]小例子

x=[0,1,2,3,4,5,6,7,8,9,10] #Input 
k=[0,1,2,3,4,5,6,5,4,10] #adjusted for speed

output I want
in this case, 5 is the first number that goes above a number that comes after it.
So I need to know the index of where 5 is located and possibly the index 
of the number that it is greater than

3 个答案:

答案 0 :(得分:5)

大于后一个值的第一个值必然对应于局部最小值中的最小值:

k = np.array([0,1,2,3,4,5,6,5,4,10])
lm_i = np.where(np.diff(np.sign(np.diff(k))) > 0)[0] + 1
mlm = np.min(k[lm_i])
mlm_i = lm_i[np.argmin(k[lm_i])]

第一个值大于后一个值的索引是第一个大于最小局部最小值的索引:

i = np.where(k > mlm)[0][0]

Plot of solution

(忽略图表看起来穿过切线处的水平线;这只是一个显示人工制品。)

作为一个单行:

np.where(k > np.min(k[np.where(np.diff(np.sign(np.diff(k))) > 0)[0] + 1]))[0][0]

请注意,这是约。比root解决方案快1000倍,因为它完全被矢量化:

%timeit np.where(k > np.min(k[np.where(np.diff(np.sign(np.diff(k))) > 0)[0] + 1]))[0][0]
1000 loops, best of 3: 228 us per loop

答案 1 :(得分:3)

矢量化解决方案,比ecatmur快约25%:

np.where(k > np.min(k[np.where(np.diff(k) < 0)[0][0]:]))[0][0]

一种天真的方法:

next(i for i in np.arange(len(arr)) if arr[i:].argmin() != 0)

答案 2 :(得分:1)

修改 拥有10,000项python for循环比在100,000,000项数组::

上运行实际上更便宜
In [14]: np.where(np.array([True if np.all(k[:j] <= k[j]) else
                            False for j in xrange(len(k))]) == 0)
Out[14]: (array([5129, 5130, 5131, ..., 6324, 6325, 6326]),)

In [15]: %timeit np.where(np.array([True if np.all(k[:j] <= k[j]) else
                                    False for j in xrange(len(k))]) == 0)
1 loops, best of 3: 201 ms per loop

就内存而言,它的成本会很高,但您可以使用广播对搜索进行矢量化。如果你这样做:

>>> k <= k[:, None]
array([[ True, False, False, ..., False, False, False],
       [ True,  True, False, ..., False, False, False],
       [ True,  True,  True, ..., False, False, False],
       ..., 
       [ True,  True,  True, ...,  True, False, False],
       [ True,  True,  True, ...,  True,  True, False],
       [ True,  True,  True, ...,  True,  True,  True]], dtype=bool)

返回的是bool数组,位置[i, j]中的项目会告诉您k[j]是否小于或等于k[i]。何时可以使用np.cumprod,如下所示:

>>> np.cumprod(k <= k[:, None], axis=1)
array([[1, 0, 0, ..., 0, 0, 0],
       [1, 1, 0, ..., 0, 0, 0],
       [1, 1, 1, ..., 0, 0, 0],
       ..., 
       [1, 1, 1, ..., 1, 0, 0],
       [1, 1, 1, ..., 1, 1, 0],
       [1, 1, 1, ..., 1, 1, 1]])

位置[i, j]中的项目会告诉您k[j]是否小于或等于k[:i]中的所有项目。如果你采用该矩阵的对角线:

>>> np.cumprod(k <= k[:, None], axis=1)[np.diag_indices(k.shape[0])]
array([1, 1, 1, ..., 1, 1, 1])

位置[i]的项目会告诉您k[i]是否小于或等于其前面的所有项目。找到该数组为零的位置:

>>> np.where(np.cumprod(k <= k[:, None],
...                     axis=1)[np.diag_indices(k.shape[0])] == 0)
(array([5129, 5130, 5131, ..., 6324, 6325, 6326]),)

并且您将获得满足您所需条件的所有值的索引。

如果您只对第一个感兴趣:

>>> np.argmax(np.cumprod(k <= k[:, None],
...                      axis=1)[np.diag_indices(k.shape[0])] == 0)
5129

这不是轻量级操作,但是如果你的内存适合所有布尔数组,它就不会让你等待太久:

In [3]: %timeit np.argmax(np.cumprod(k <= k[:, None],
                                     axis=1)[np.diag_indices(k.shape[0])] == 0)
1 loops, best of 3: 948 ms per loop