如何在 numba 中向矩阵添加行

问题描述 投票:0回答:1

我需要将一个“行”数组(1x4)添加到 Numba 中的矩阵(Nx4)

import numpy as np
from numba import njit

@njit
def loop_append(arr, row_arr):
    arr2 = arr.copy()
    for i in range(5):
        arr2 = np.append(arr2,row_arr)

    return arr2




# Creating a numpy array of random floats with size 10x4
arr = np.random.rand(10, 4)
row_arr = np.random.rand(1, 4)

arr2 = loop_append(arr,row_arr)

print(arr2)

但是我收到这个错误。我也尝试过 vstack 和 concatenate。

错误:

Cannot unify array(float64, 2d, C) and array(float64, 1d, C) for 'arr2.2', defined at C:\Test\numba_append.py (7)

File "numba_append.py", line 7:
def loop_append(arr, row_arr):
    <source elided>
    arr2 = arr.copy()
    for i in range(5):
    ^

During: typing of assignment at C:\Test\numba_append.py (7)

File "numba_append.py", line 7:
def loop_append(arr, row_arr):
    <source elided>
    arr2 = arr.copy()
    for i in range(5):
    ^


Process finished with exit code 1
python-3.x numba
1个回答
0
投票

简短回答:

只需添加

axis=0

@njit
def loop_append(arr, row_arr):
    arr2 = arr.copy()
    for i in range(5):
        arr2 = np.append(arr2, row_arr, axis=0)  # Added axis=0.

    return arr2

长答案:

根据官方文档

np.append

如果未给出 axis,则 arr 和 value 在使用前都会被展平。

这意味着在您的原始代码中(没有

axis
参数),
np.append
的返回值是一个一维数组。但是,您尝试将其重新分配给
arr2
,这是一个二维数组。 Numba 将一维和二维数组视为不同的类型,因此此操作不起作用。

@njit
def loop_append(arr, row_arr):
    arr_2d = arr.copy()
    for i in range(5):
        arr_1d = np.append(arr_2d, row_arr)

        # You are trying to assign a 1D array to a 2D array variable here.
        arr_2d = arr_1d

    return arr_2d

这就是错误消息抱怨的内容。

Cannot unify array(float64, 2d, C) and array(float64, 1d, C) for 'arr2.2', ...
                            ^^                        ^^

因此,您需要做的是确保在添加行之前和之后数组的维数不会改变。

此外,正如评论中指出的,

np.append
创建一个新数组并执行深层复制。对于“单个”添加操作来说,这不是值得担心的事情,但如果您重复使用它,则需要担心。特别是在处理大型数组或添加许多行时,它会对性能产生重大影响。 这是基准:

import timeit import numpy as np from numba import njit @njit def loop_append(arr, row_arr, n): if n == 0: return arr.copy() arr2 = arr # No need for a copy here. for i in range(n): arr2 = np.append(arr2, row_arr, axis=0) return arr2 @njit def loop_preallocate(arr, row_arr, n): assert row_arr.ndim == 2 and row_arr.shape[0] == 1 arr2 = np.empty((arr.shape[0] + n, arr.shape[1]), dtype=arr.dtype) arr2[:arr.shape[0]] = arr for i in range(n): arr2[arr.shape[0] + i] = row_arr return arr2 def test(): arr = np.random.rand(10000, 100) row_arr = np.random.rand(1, 100) n = 10 r1 = loop_append(arr, row_arr, n) r2 = loop_preallocate(arr, row_arr, n) assert r1.shape == (arr.shape[0] + row_arr.shape[0] * n, arr.shape[1]) assert np.array_equal(r1, r2) def benchmark(f): number, time_taken = timeit.Timer(lambda: f(arr, row_arr, n)).autorange() print(f"{f.__name__}: {1000 * time_taken / number:.3f} ms") benchmark(loop_append) benchmark(loop_preallocate) if __name__ == '__main__': test()

loop_append: 15.892 ms
loop_preallocate: 1.831 ms
	
© www.soinside.com 2019 - 2024. All rights reserved.