NumPy:在矢量化赋值期间Evaulate索引数组

时间:2021-08-09 01:28:46

I would like to vectorize this NumPy operation:

我想对这个NumPy操作进行矢量化:

for j in range(yt):
    for i in range(xt):
        y[j, i] = x[idx[j, i], j, i]

where idx contains axis-0 index to an x slice. Is there some simple way to do this?

其中idx包含x切片的axis-0索引。有一些简单的方法可以做到这一点吗?

2 个解决方案

#1


7  

You can use:

您可以使用:

J, I = np.ogrid[:yt, :xt]
x[idx, J, I]

Here is the test:

这是测试:

import numpy as np

yt, xt = 3, 5
x = np.random.rand(10, 6, 7)
y = np.zeros((yt, xt))
idx = np.random.randint(0, 10, (yt, xt))

for j in range(yt):
    for i in range(xt):
        y[j, i] = x[idx[j, i], j, i]

J, I = np.ogrid[:yt, :xt]
np.all(x[idx, J, I] == y)

#2


0  

Here's one approach using linear indexing -

这是使用线性索引的一种方法 -

zt,yt,xt = x.shape
out = x.reshape(zt,-1)[idx.ravel(),np.arange(yt*xt)].reshape(-1,xt)

Runtime tests & verify output

运行时测试并验证输出

This section compares the proposed approach in this post and the other orgid based solution on performance and also verifies the outputs.

本节比较了本文中提出的方法和其他基于orgid的性能解决方案,并验证了输出。

Function definitions -

功能定义 -

def original_app(x,idx):
    _,yt,xt = x.shape
    y = np.zeros((yt,xt))
    for j in range(yt):
        for i in range(xt):
            y[j, i] = x[idx[j, i], j, i]
    return y

def ogrid_based(x,idx):
    _,yt,xt = x.shape
    J, I = np.ogrid[:yt, :xt]
    return x[idx, J, I]

def reshape_based(x,idx):                               
    zt,yt,xt = x.shape
    return x.reshape(zt,-1)[idx.ravel(),np.arange(yt*xt)].reshape(-1,xt)

Setup inputs -

设置输入 -

In [56]: # Inputs
    ...: zt,yt,xt = 100,100,100
    ...: x = np.random.rand(zt,yt,xt)
    ...: idx = np.random.randint(0,zt,(yt,xt))
...: 

Verify outputs -

验证输出 -

In [57]: np.allclose(original_app(x,idx),ogrid_based(x,idx))
Out[57]: True

In [58]: np.allclose(original_app(x,idx),reshape_based(x,idx))
Out[58]: True

Timings -

In [68]: %timeit original_app(x,idx)
100 loops, best of 3: 6.97 ms per loop

In [69]: %timeit ogrid_based(x,idx)
1000 loops, best of 3: 391 µs per loop

In [70]: %timeit reshape_based(x,idx)
1000 loops, best of 3: 230 µs per loop

#1


7  

You can use:

您可以使用:

J, I = np.ogrid[:yt, :xt]
x[idx, J, I]

Here is the test:

这是测试:

import numpy as np

yt, xt = 3, 5
x = np.random.rand(10, 6, 7)
y = np.zeros((yt, xt))
idx = np.random.randint(0, 10, (yt, xt))

for j in range(yt):
    for i in range(xt):
        y[j, i] = x[idx[j, i], j, i]

J, I = np.ogrid[:yt, :xt]
np.all(x[idx, J, I] == y)

#2


0  

Here's one approach using linear indexing -

这是使用线性索引的一种方法 -

zt,yt,xt = x.shape
out = x.reshape(zt,-1)[idx.ravel(),np.arange(yt*xt)].reshape(-1,xt)

Runtime tests & verify output

运行时测试并验证输出

This section compares the proposed approach in this post and the other orgid based solution on performance and also verifies the outputs.

本节比较了本文中提出的方法和其他基于orgid的性能解决方案,并验证了输出。

Function definitions -

功能定义 -

def original_app(x,idx):
    _,yt,xt = x.shape
    y = np.zeros((yt,xt))
    for j in range(yt):
        for i in range(xt):
            y[j, i] = x[idx[j, i], j, i]
    return y

def ogrid_based(x,idx):
    _,yt,xt = x.shape
    J, I = np.ogrid[:yt, :xt]
    return x[idx, J, I]

def reshape_based(x,idx):                               
    zt,yt,xt = x.shape
    return x.reshape(zt,-1)[idx.ravel(),np.arange(yt*xt)].reshape(-1,xt)

Setup inputs -

设置输入 -

In [56]: # Inputs
    ...: zt,yt,xt = 100,100,100
    ...: x = np.random.rand(zt,yt,xt)
    ...: idx = np.random.randint(0,zt,(yt,xt))
...: 

Verify outputs -

验证输出 -

In [57]: np.allclose(original_app(x,idx),ogrid_based(x,idx))
Out[57]: True

In [58]: np.allclose(original_app(x,idx),reshape_based(x,idx))
Out[58]: True

Timings -

In [68]: %timeit original_app(x,idx)
100 loops, best of 3: 6.97 ms per loop

In [69]: %timeit ogrid_based(x,idx)
1000 loops, best of 3: 391 µs per loop

In [70]: %timeit reshape_based(x,idx)
1000 loops, best of 3: 230 µs per loop