沿着新维度将1D numpy数组添加到2D数组(维度不匹配)

7cwmlq89  于 2023-04-21  发布在  其他
关注(0)|答案(3)|浏览(100)

我想添加一个一维数组到二维数组沿着二维数组的第二个维度使用以下代码中的逻辑。

import numpy as np
TwoDArray = np.random.randint(0, 10, size=(10000, 50))
OneDArray = np.random.randint(0, 10, size=(2000))
Sum = np.array([(TwoDArray+element).sum(axis=1) for element in OneDArray]).T
print(Sum.shape)
>> (10000, 2000)

这个列表理解非常慢。什么是最快的方法?(我猜是用数组计算)。

EDIT我尝试了以下方法,但运行时间最差

Sum = np.sum(TwoDArray[:, np.newaxis, :] + OneDArray[np.newaxis, :, np.newaxis], axis=2)

我也试过用Numba,但运行时间是一样的。

@jit(nopython=True)
def compute_sum(TwoDArray, OneDArray):
    return [(TwoDArray+element).sum(axis=1) for element in OneDArray]
piok6c0g

piok6c0g1#

由于我们将相同的值(1D数组的每个元素)添加到2D数组中,这相当于将每个轴的总和加上1D数组**乘以2D数组第二个轴的维度。我们还必须向1D数组添加一个新的轴,否则形状不匹配。

import numpy as np

arr2d = np.random.randint(0, 10, size=(10000, 50))
arr1d = np.random.randint(0, 10, size=2000)
arr_sum = np.array([(arr2d+element).sum(axis=1) for element in arr1d]).T

out = (arr2d.sum(axis=1) + (arr1d * arr2d.shape[1])[:, np.newaxis]).T

print(out.shape == arr_sum.shape) # True
print(np.allclose(out, arr_sum))  # True

In [22]: %timeit np.array([(arr2d+element).sum(axis=1) for element in arr1d]).T
1.86 s ± 20.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [23]: %timeit (arr2d.sum(axis=1) + (arr1d * arr2d.shape[1])[:, np.newaxis]).T
25.8 ms ± 226 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
uoifb46i

uoifb46i2#

如果你想编写一个高性能的Numba实现,你必须编写简单的循环,或者在某些情况下使用BLAS函数。

实施例1

import numba as nb
import numpy as np

@nb.njit(fastmath=True,parallel=True,cache=True)
def cust_sum(TwoDArray,OneDArray):
    #allocate Output
    res=np.empty((TwoDArray.shape[0],OneDArray.shape[0]),dtype=TwoDArray.dtype)

    for i in nb.prange(TwoDArray.shape[0]):
        for j in range(OneDArray.shape[0]):
            acc=0
            for k in range(TwoDArray.shape[1]):
                acc+=TwoDArray[i,k]+OneDArray[j]
            res[i,j]=acc
    return res

%timeit sum_2=cust_sum(TwoDArray,OneDArray)
#12.8 ms ± 498 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

编辑:示例2

与一些想法从弥敦道炉回答这可以修改为

@nb.njit(fastmath=True,parallel=True,cache=True)
def cust_sum_2(TwoDArray,OneDArray):
    #allocate Output
    res=np.empty((TwoDArray.shape[0],OneDArray.shape[0]),dtype=TwoDArray.dtype)

    for i in nb.prange(TwoDArray.shape[0]):
        acc=0
        for k in range(TwoDArray.shape[1]):
            acc+=TwoDArray[i,k]
        for j in range(OneDArray.shape[0]):
            res[i,j]=acc+OneDArray[j]*TwoDArray.shape[1]
    return res

%timeit sum_2=cust_sum_2(TwoDArray,OneDArray)
#7.25 ms ± 815 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

print(np.allclose(cust_sum_2(TwoDArray,OneDArray),Sum))
#True
snz8szmq

snz8szmq3#

Change - Sum = np.array([(TwoDArray+element).sum(axis=1)for element in OneDArray]).T

import numpy as np

TwoDArray = np.random.randint(0, 10, size=(10000, 50))
OneDArray = np.random.randint(0, 10, size=(2000))

Sum = TwoDArray.dot(np.ones((50, 2000))) + OneDArray

print(Sum.shape)

相关问题