簡體   English   中英

附加到 numpy 數組或 for 循環內的列表 - 這是可取的?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM