[英]Appending to a numpy array or list inside a for loop- which is prefferable?
所以我正在編寫一些代碼,如下所示:
import numpy as np
A=np.array([[1,0,3,5,7],[4,0,6,2,3]])
def SMD(matrix):
if isinstance(matrix,np.ndarray)==False:
raise ValueError('The needed datatype is an array')
else:
m= matrix.shape[0]
n= matrix.shape[1]
a=np.array([])
b=np.array([0])
c=np.array([])
for i in range(m):
for j in range(n):
if matrix[i][j] !=0:
np.append(a,matrix[i][j])
np.append(c,j)
np.append(b,len(a))
return a,b,c
但是,在這種情況下,numpy append 對我不起作用。 如果我改為使用列表而不是 arrays,則代碼運行良好:
def SMD(matrix):
if isinstance(matrix,np.ndarray)==False:
raise ValueError('The needed datatype is an array')
else:
m= matrix.shape[0]
n= matrix.shape[1]
d=[]
e=[0]
f=[]
for i in range(m):
for j in range(n):
if matrix[i][j] !=0:
d.append(matrix[i][j])
f.append(j)
e.append(len(d))
return d,e,f
想要的 output 是:
[1, 3, 5, 7, 4, 6, 2, 3], [0, 4, 8], [0, 2, 3, 4, 0, 2, 3, 4]
或作為 arrays(取決於使用的代碼)。
當然,我想知道為什么第一個代碼不起作用。
據我所知,就計算速度而言,使用 arrays 可能更好,但在這種情況下,它有什么不同嗎?
謝謝
在效率方面,您應該避免循環
def SMD(matrix):
bool_matrix = (matrix!=0)
return (
matrix[bool_matrix],
np.append(0, bool_matrix.sum(1).cumsum()),
np.where(bool_matrix)[1]
)
SMD(A)
#(array([1, 3, 5, 7, 4, 6, 2, 3]),
# array([0, 4, 8]),
# array([0, 2, 3, 4, 0, 2, 3, 4]))
matrix[bool_matrix]
只是matrix
的所有非零元素
np.append(0, bool_matrix.sum(1).cumsum())
首先計算matrix
行中非零元素的數量; 然后它計算累積和(從第一行到最后一行); 最后它在數組的開頭添加0
。
np.where(bool_matrix)[1]
告訴您matrix
元素非零的列的索引。
np.append
返回附加的數組,它不會就地執行 append。 所以你必須保存返回的值。
固定代碼:
import numpy as np
A=np.array([[1,0,3,5,7],[4,0,6,2,3]])
def SMD(matrix):
if isinstance(matrix,np.ndarray)==False:
raise ValueError('The needed datatype is an array')
else:
m= matrix.shape[0]
n= matrix.shape[1]
a=np.array([])
b=np.array([0])
c=np.array([])
for i in range(m):
for j in range(n):
if matrix[i][j] !=0:
a = np.append(a,matrix[i][j])
c = np.append(c,j)
b = np.append(b,len(a))
return a,b,c
由於您使用的是 numpy 您也可以對其進行矢量化並避免循環:
a = A[A!=0]
b = np.pad(np.cumsum(np.sum(A!=0,axis=1)), (1,0))
c = np.argwhere(A!=0)[:, 1]
print (a,b,c)
Output:
[1 3 5 7 4 6 2 3] [0 4 8] [0 2 3 4 0 2 3 4]
2 個版本的運行時間(由ags29
)
列表:
In [91]: timeit SMD(A)
8.76 µs ± 67 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
大批:
In [92]: timeit SMD1(A)
206 µs ± 198 ns per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
np.append
是 np.concatenate 的一個糟糕的名稱覆蓋np.concatenate
。 可以將一個元素添加到數組中 - 只要您注意文檔。 但就像concatenate
(以及所有stack
函數)一樣,它不會就地運行。 它返回一個新數組,這使得它在重復執行時要慢得多(在這樣的循環中)。
數組 append output:
In [90]: SMD1(A)
Out[90]:
(array([1., 3., 5., 7., 4., 6., 2., 3.]),
array([0, 4, 8]),
array([0., 2., 3., 4., 0., 2., 3., 4.]))
如果您確實需要數組 output,我們通常建議執行列表 append,並以一個np.array(alist)
包裝器結尾。
列表版本仍然比無循環數組替代方案更快:
薩爾瓦多:
In [98]: timeit SMD2(A)
34.1 µs ± 58.4 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
穆吉加的:
In [101]: timeit SMD3(A)
100 µs ± 51.8 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
如果我重寫您的 function 以使用嵌套列表,我會得到更好的時間:
In [118]: def SMD5(matrix):
...: m= len(matrix)
...: n= len(matrix[0])
...: d=[]
...: e=[0]
...: f=[]
...: for i in range(m):
...: for j in range(n):
...: if matrix[i][j] !=0:
...: d.append(matrix[i][j])
...: f.append(j)
...: e.append(len(d))
...: return d,e,f
In [120]: timeit SMD5(A.tolist())
3.94 µs ± 159 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
對於更大的陣列,我希望 Salvatore 的版本能夠更好地擴展。
因此,您的代碼不起作用的原因是您沒有將np.append
操作的 output 分配回a,b,c
。 以下是您的代碼的有效版本:
def SMD(matrix):
if isinstance(matrix,np.ndarray)==False:
raise ValueError('The needed datatype is an array')
else:
m= matrix.shape[0]
n= matrix.shape[1]
a=np.array([])
b=np.array([0])
c=np.array([])
for i in range(m):
for j in range(n):
if matrix[i,j] !=0:
a = np.append(a,matrix[i,j])
c = np.append(c,j)
b = np.append(b,len(a))
return a,b,c
在效率方面,最好用正確的大小預先初始化a,b,c
(使用例如np.empty
),然后在循環中分配值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.