2016-11-14 163 views
5

我注意到通過「直接」迭代通過numpy數組迭代通過tolist方法迭代之間有意義的區別。見下面定時:什麼是迭代通過一個numpy數組最快的方法

直接
[i for i in np.arange(10000000)]
經由tolist
[i for i in np.arange(10000000).tolist()]

enter image description here


考慮到我發現了一種更快的方法。我想問問還有什麼可以讓它變得更快?

什麼是最快的方式來遍歷一個numpy數組?

+0

*是*奇數。我自己嘗試了好幾次,似乎將它轉換爲列表確實使其始終更快。感謝您將此帶入光明中。 –

+1

只需迭代並獲取列表或做一些處理呢?使用'list(np.arange(1000000))'看起來非常快。 – Divakar

+0

@Divakar參見http://stackoverflow.com/a/40575522/2336654 – piRSquared

回答

4

這些都是我的機器慢

In [1034]: timeit [i for i in np.arange(10000000)] 
1 loop, best of 3: 2.16 s per loop 

上計時,如果我直接生成的範圍(PY3所以這是一個genertor)倍要好得多。以此爲基礎來理解這個尺寸的列表。

In [1035]: timeit [i for i in range(10000000)] 
1 loop, best of 3: 1.26 s per loop 

tolist首先將arange轉換爲列表;需要更長的時間,但迭代仍然是一個列表

In [1036]: timeit [i for i in np.arange(10000000).tolist()] 
1 loop, best of 3: 1.6 s per loop 

使用list()上 - 同時在陣列上直接迭代;這表明直接迭代首先執行此操作。

In [1037]: timeit [i for i in list(np.arange(10000000))] 
1 loop, best of 3: 2.18 s per loop 

In [1038]: timeit np.arange(10000000).tolist() 
1 loop, best of 3: 927 ms per loop 

同一時間在.tolist

In [1039]: timeit list(np.arange(10000000)) 
1 loop, best of 3: 1.55 s per loop 

一般來說,如果你必須循環迭代一個,名單上的工作速度更快。訪問列表中的元素更簡單。

查看索引返回的元素。

a[0]是另一個numpy對象;它由a中的值構成,但不是簡單的取值

list(a)[0]是同一類型;該列表只是[a[0], a[1], a[2]]]

In [1043]: a = np.arange(3) 
In [1044]: type(a[0]) 
Out[1044]: numpy.int32 
In [1045]: ll=list(a) 
In [1046]: type(ll[0]) 
Out[1046]: numpy.int32 

tolist陣列成純列表轉換,在這種情況下,作爲整數的列表。它比list()做更多的工作,但它在編譯代碼。

In [1047]: ll=a.tolist() 
In [1048]: type(ll[0]) 
Out[1048]: int 

一般不要使用list(anarray)。它很少做任何有用的事情,並且不如tolist()那樣強大。

迭代數組的最快方式是什麼 - 無。至少不在Python中;在c代碼中有快速的方法。

a.tolist()是從數組創建列表整數的最快矢量化方法。它迭代,但在編譯代碼中這樣做。

但是你真正的目標是什麼?

+0

感謝@hpaulj這非常接近實際回答我的問題,因爲你陳述了......「什麼是迭代數組的最快方法 - 無。」我可能會選擇這個作爲我的答案,但我會稍微打開它。 – piRSquared

7

這實際上並不奇怪。讓我們從最慢的一個時間開始研究這些方法。

[i for i in np.arange(10000000)] 

此方法要求蟒伸入numpy的陣列(存儲在C存儲器範圍),一個元件的時間,在存儲器分配Python對象,並創建一個指針列表中的該對象。每次你在存儲在C後端的numpy數組之間進行管道操作並將其拉入純python時,會產生間接費用。這種方法增加了10,000,000次的成本。

下一頁:

[i for i in np.arange(10000000).tolist()] 

在這種情況下,使用.tolist()使得單個調用numpy的Ç後端和分配所有一次性的元素添加到列表中。然後您使用python遍歷該列表。

最後:

list(np.arange(10000000)) 

這基本上做同樣的事情如上,但它創造numpy的原生類型對象(例如np.int64)的列表。使用list(np.arange(10000000))np.arange(10000000).tolist()應該差不多同時。


所以,在迭代而言,使用numpy的主要優點是你不需要進行迭代。操作以向量化的方式應用於陣列。迭代只會減慢速度。如果你發現自己迭代數組元素,你應該尋找一種方法來重構你正在嘗試的算法,這種方式只使用numpy操作(它有很多內建的!),或者如果真的有必要,你可以使用np.apply_along_axis,np.apply_over_axisnp.vectorize

+2

但是'list(np.arange(10))'和'np.arange(10).tolist()'之間存在細微的差別:第一個會導致一個「np.int64」列表的第二個Python的int列表。第一個問題可能會導致序列化等問題。使用json。 json會在第一個錯誤,因爲它不能處理'np.int64' – MaxNoe

+0

你是絕對正確的。 – James

+0

這是非常有用的,這就是爲什麼我投了贊成票,我希望別人也這麼做。我現在要解決這個問題了,因爲我仍然希望看到通過數組進行迭代的其他選項。 – piRSquared

相關問題