我有一个带有整数值的NumPy数组。矩阵的值的范围是从0到矩阵中的最大元素(换句话说,其中显示的所有数字是从0到最大数据元素)。我需要建立有效的(
有效的手段是快速的完全矢量化解决方案 )来搜索每一行中的元素数量,并根据矩阵值对它们进行编码。
我找不到类似的问题,或者以某种方式帮助解决了这个问题。
所以如果我data
在输入中有这个:
# shape is (N0=4, m0=4)
1 1 0 4
2 4 2 1
1 2 3 5
4 4 4 1
所需的输出是:
# shape(N=N0, m=data.max()+1):
1 2 0 0 1 0
0 1 2 0 1 0
0 1 1 1 0 1
0 1 0 0 3 0
我知道如何解决这个问题,方法是简单地逐一data
迭代的每一行中计算唯一值,然后结合考虑data
数组中所有可能值的结果。
使用NumPy进行矢量化处理时,关键问题在于逐个搜索每个数字的速度很慢,并且假设存在很多唯一数字,但这并不是有效的解决方案。通常N
,唯一数字计数都很大(顺便说一句,N
似乎比唯一数字计数大)。
有人有好主意吗?)
嗯,这基本上是做np.bincount
与做1D
阵列。但是,我们需要在每行上迭代使用它(简单地考虑一下)。为了使其向量化,我们可以使每行偏移最大数量。想法是每行具有不同的bin,以使它们不受编号相同的其他行元素的影响。
因此,实施将是-
# Vectorized solution
def bincount2D_vectorized(a):
N = a.max()+1
a_offs = a + np.arange(a.shape[0])[:,None]*N
return np.bincount(a_offs.ravel(), minlength=a.shape[0]*N).reshape(-1,N)
样品运行-
In [189]: a
Out[189]:
array([[1, 1, 0, 4],
[2, 4, 2, 1],
[1, 2, 3, 5],
[4, 4, 4, 1]])
In [190]: bincount2D_vectorized(a)
Out[190]:
array([[1, 2, 0, 0, 1, 0],
[0, 1, 2, 0, 1, 0],
[0, 1, 1, 1, 0, 1],
[0, 1, 0, 0, 3, 0]])
Numba调整
我们可以带来numba
进一步的提速。现在,numba
允许进行一些调整。
首先,它允许JIT编译。
同样,最近他们引入了实验性parallel
功能,该功能可自动并行化已知具有并行语义的功能中的操作。
最终的调整将prange
用作的替代range
。文档指出,这可以并行运行循环,类似于OpenMP并行循环和Cython的prange。prange
在较大的数据集上表现良好,这可能是由于设置并行工作所需的开销。
因此,通过这两项新的调整以及njit
针对非Python模式的调整,我们将获得三种变体-
# Numba solutions
def bincount2D_numba(a, use_parallel=False, use_prange=False):
N = a.max()+1
m,n = a.shape
out = np.zeros((m,N),dtype=int)
# Choose fucntion based on args
func = bincount2D_numba_func0
if use_parallel:
if use_prange:
func = bincount2D_numba_func2
else:
func = bincount2D_numba_func1
# Run chosen function on input data and output
func(a, out, m, n)
return out
@njit
def bincount2D_numba_func0(a, out, m, n):
for i in range(m):
for j in range(n):
out[i,a[i,j]] += 1
@njit(parallel=True)
def bincount2D_numba_func1(a, out, m, n):
for i in range(m):
for j in range(n):
out[i,a[i,j]] += 1
@njit(parallel=True)
def bincount2D_numba_func2(a, out, m, n):
for i in prange(m):
for j in prange(n):
out[i,a[i,j]] += 1
为了完整起见并在以后进行测试,该循环版本为-
# Loopy solution
def bincount2D_loopy(a):
N = a.max()+1
m,n = a.shape
out = np.zeros((m,N),dtype=int)
for i in range(m):
out[i] = np.bincount(a[i], minlength=N)
return out
运行时测试
情况1 :
In [312]: a = np.random.randint(0,100,(100,100))
In [313]: %timeit bincount2D_loopy(a)
...: %timeit bincount2D_vectorized(a)
...: %timeit bincount2D_numba(a, use_parallel=False, use_prange=False)
...: %timeit bincount2D_numba(a, use_parallel=True, use_prange=False)
...: %timeit bincount2D_numba(a, use_parallel=True, use_prange=True)
10000 loops, best of 3: 115 µs per loop
10000 loops, best of 3: 36.7 µs per loop
10000 loops, best of 3: 22.6 µs per loop
10000 loops, best of 3: 22.7 µs per loop
10000 loops, best of 3: 39.9 µs per loop
案例2:
In [316]: a = np.random.randint(0,100,(1000,1000))
In [317]: %timeit bincount2D_loopy(a)
...: %timeit bincount2D_vectorized(a)
...: %timeit bincount2D_numba(a, use_parallel=False, use_prange=False)
...: %timeit bincount2D_numba(a, use_parallel=True, use_prange=False)
...: %timeit bincount2D_numba(a, use_parallel=True, use_prange=True)
100 loops, best of 3: 2.97 ms per loop
100 loops, best of 3: 3.54 ms per loop
1000 loops, best of 3: 1.83 ms per loop
100 loops, best of 3: 1.78 ms per loop
1000 loops, best of 3: 1.4 ms per loop
案例3:
In [318]: a = np.random.randint(0,1000,(1000,1000))
In [319]: %timeit bincount2D_loopy(a)
...: %timeit bincount2D_vectorized(a)
...: %timeit bincount2D_numba(a, use_parallel=False, use_prange=False)
...: %timeit bincount2D_numba(a, use_parallel=True, use_prange=False)
...: %timeit bincount2D_numba(a, use_parallel=True, use_prange=True)
100 loops, best of 3: 4.01 ms per loop
100 loops, best of 3: 4.86 ms per loop
100 loops, best of 3: 3.21 ms per loop
100 loops, best of 3: 3.18 ms per loop
100 loops, best of 3: 2.45 ms per loop
看起来这些numba
变体的效果非常好。从三个变体中选择一个将取决于输入数组的形状参数,并在某种程度上取决于其中的唯一元素的数量。
问题内容: 和是先前已计算出的相同长度的NumPy向量,因此需要创建一个新向量。在它只是为了说明什么是想要的元素索引。 在这种情况下是否需要for循环? 问题答案: 您可能认为这会起作用: 但事实并非如此:您实际上无法以这种方式在numpy中进行递归(因为numpy计算了整个RHS,然后将其分配给LHS)。 因此,除非您可以提出该公式的非递归版本,否则您将陷入显式循环:
问题内容: 假设我有一个numpy数组: 我有一个对应的“向量”: 我如何沿每一行进行减法或除法运算,所以结果是: 长话短说:如何使用对应于每一行的1D标量数组在2D数组的每一行上执行操作? 问题答案: 干得好。您只需要与广播结合使用(或):
例如,对于 我想得到 有没有办法不用for循环或使用? 编辑:实际数据由1000行组成,每行100个元素,每个元素的范围从1到365。最终目标是确定有重复的行的百分比。这是一个作业问题,我已经解决了(用for循环),但我只是想知道是否有更好的方法来做它与Numpy。
问题内容: 我有2 x 4和3 x 4的矩阵。我想找到各行之间的欧几里得距离,并在最后得到2 x 3的矩阵。这是一个带for循环的代码,它针对所有b行向量计算a中每个行向量的欧式距离。在不使用for循环的情况下该如何做? 问题答案: 只需在正确的位置使用:
问题内容: 我出现了不想要的行为,即,它更改了进入原始函数的参数的数据类型。我最初的问题是关于一般情况的,我将使用这个新问题来提出更具体的情况。 (为什么要问第二个问题?为了说明问题,我创建 了一个关于更具体案例 的问题-从具体问题到更一般的问题总是比较容易。而且我 单独 创建了这个问题,因为我认为这是有助于保持一般情况以及对一般情况的答复(应该找到),而不会因为考虑解决任何特定问题而受到“污染”
问题内容: 我在2D数组上恒定大小的移动窗口上执行操作。我可以实现高效的类似于矢量化的操作来执行此操作而无需在Python中循环吗?我目前的结构看起来像这样 这些评论可以 吃 留在这个问题暗指矢量化这种操作这种可能性,但没有进一步的细节矢量索引/切片在numpy的/SciPy的? 问题答案: 如果可以表达功能 作为一个线性算,你可以使用SciPy的的signal.convolve2d函数来做到这一