我需要将一个“行”数组(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
只需添加
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