元素智能广播用于比较两个NumPy的阵列?

问题描述 投票:5回答:3

比方说,我有一个这样的数组:

import numpy as np

base_array = np.array([-13, -9, -11, -3, -3, -4,   2,  2,
                         2,  5,   7,  7,  8,  7,  12, 11])

假设我想知道:“有多少元素在base_array是大于4”这可以简单地通过利用广播来完成:

np.sum(4 < base_array)

对于这个问题的答案是7。现在,假设而不是与单个的价值,我想这样做在一个阵列。换句话说,在c每个值comparison_array,找出base_array的很多元素是如何比c更大。如果我这样做了简单的方式,它显然失败,因为它不知道如何正确地播放它:

comparison_array = np.arange(-13, 13)
comparison_result = np.sum(comparison_array < base_array)

输出:

Traceback (most recent call last):
  File "<pyshell#87>", line 1, in <module>
    np.sum(comparison_array < base_array)
ValueError: operands could not be broadcast together with shapes (26,) (16,) 

如果我能以某种方式有comparison_array的每个元素拿到转播到base_array的形状,这将解决这个问题。但我不知道该怎么办这样一个“元素智能广播”。

现在,我只知道我如何实现这个使用列表理解这两种情况下:

first = sum([4 < i for i in base_array])
second = [sum([c < i for i in base_array])
          for c in comparison_array]
print(first)
print(second)

输出:

7
[15, 15, 14, 14, 13, 13, 13, 13, 13, 12, 10, 10, 10, 10, 10, 7, 7, 7, 6, 6, 3, 2, 2, 2, 1, 0]

但我们都知道,这将是数量级比上更大的阵列正确矢量化numpy执行较慢的订单。所以,我应该怎么办这numpy,这样它的速度快?理论上讲,该解决方案应扩展到任何类型的操作,其中广播作品,而不仅仅是大于或低于这个例子。

python arrays numpy vectorization numpy-broadcasting
3个回答
4
投票

你可以简单的维度添加到比较阵列,因此比较沿新维度“延伸”所有值。

>>> np.sum(comparison_array[:, None] < base_array)
228

这是broadcasting的基本原则,并适用于所有类型的操作。

如果你需要沿轴进行的总和,你只需指定沿着你想要的比较后总结轴。

>>> np.sum(comparison_array[:, None] < base_array, axis=1)
array([15, 15, 14, 14, 13, 13, 13, 13, 13, 12, 10, 10, 10, 10, 10,  7,  7,
        7,  6,  6,  3,  2,  2,  2,  1,  0])

1
投票

您将要转一个阵列用于广播正常工作。当您播送两个数组在一起,尺寸一字排开,任何单位尺寸有效地扩展到它们匹配的非单元大小。所以尺寸(16, 1)(原阵列)和(1, 26)(比较阵列)的两个阵列将广播给(16, 26)

不要忘了跨越大小16的尺寸来概括:

(base_array[:, None] > comparison_array).sum(axis=1)

None在片中相当于np.newaxis:它是多方面的指定索引处插入一个新的单元尺寸之一。你不需要做comparison_array[None, :]的原因是,广播排队最高的尺寸,并且在自动最低,那些充满。


1
投票

这里有一个与专注于存储效率,从而表现np.searchsorted -

def get_comparative_sum(base_array, comparison_array):
    n = len(base_array)
    base_array_sorted = np.sort(base_array)
    idx = np.searchsorted(base_array_sorted, comparison_array, 'right')
    idx[idx==n] = n-1
    return n - idx - (base_array_sorted[idx] == comparison_array)

计时 -

In [40]: np.random.seed(0)
    ...: base_array = np.random.randint(-1000,1000,(10000))
    ...: comparison_array = np.random.randint(-1000,1000,(20000))

# @miradulo's soln
In [41]: %timeit np.sum(comparison_array[:, None] < base_array, axis=1)
1 loop, best of 3: 386 ms per loop

In [42]: %timeit get_comparative_sum(base_array, comparison_array)
100 loops, best of 3: 2.36 ms per loop
© www.soinside.com 2019 - 2024. All rights reserved.