在哪些方面,Numpy的速度反而比不上原始Python?

本來只是想測試下numpy處理數組索引時是不是從頭到尾順序查找的,就寫了這一段:

import numpy as np
a = np.random.rand(100)
b = a.tolist()
%timeit a[0]
%timeit a[50]
%timeit a[99]
%timeit b[0]
%timeit b[50]
%timeit b[99]

結果很有意思

10000000 loops, best of 3: 178 ns per loop
10000000 loops, best of 3: 187 ns per loop
10000000 loops, best of 3: 189 ns per loop
10000000 loops, best of 3: 82 ns per loop
10000000 loops, best of 3: 74 ns per loop
10000000 loops, best of 3: 74.2 ns per loop

也就是說numpy查找一個下標時應該是順序的(查找a[0]快於a[50]快於a[99])

標準的list反而不是順序的(查找a[50]快於a[99]快於a[0])

最關鍵的是!numpy array比list要慢一倍以上!不能忍啊!

不過想想也是,numpy array是一個複雜的結構體,list就只是個list···

這樣的話,要優化代碼,把原始碼盡量改成Numpy就沒有意義了···

我的問題就在這裡了,在處理什麼任務時,Numpy的數據結構和函數反而不如原始Python更快?


很有意思的結果。我不清楚numpy數組在哪些場合下慢過list,不過糾正一下題主的誤解。

python的list實現不是鏈表,而是動態數組。動態數組append/pop的均攤時間複雜度為O(1),而按下標隨機訪問跟一般數組無異,時間複雜度嚴格為O(1)。C++ STL中的vector也是動態數組。當然,從非尾部增刪元素也是支持的,雖然慢就是了,應避免。

關於python各種內建類型操作的時間複雜度,可參考TimeComplexity

關於動態數組,可參考Dynamic array

另外numpy數組單個元素隨機訪問比list慢沒啥大不了的,後者是python實現內建,前者還有ffi的開銷。numpy快的地方在於可以整向量/整矩陣地做算術運算,中間省了許多開銷。你寫個list comprehension來用list模擬向量算術,再來跟numpy比,會有質的不同。哪怕沒鏈MKL優化的numpy也能把list爆出翔。


你這個問題其實不說明numpy比原始的Python慢,而是說明了數據轉換是有性能損耗的。

numpy內部存儲數據是和C語言一致的,比如一個這裡100個np.float64的元素就是內存中緊密排列的100個double數字。

而Python里的所有東西,包括簡單的數字,全都是PyObject的指針,每個PyObject都要在堆上分配,記錄引用計數,類型等許多bookkeeping的數據。你訪問a[0]時,這個數字本來只是一個簡單的double,但是返回到Python裡面就需要在堆上分配並加很多額外信息;而b[0]不同,Python里的list本來就是PyObject *的數組,這些額外的信息都創建好了,所以更快。

這唯一告訴我們的就是,不要把numpy的計算和Python內置的功能混在一起用,除了到了最後輸入輸出的時候。


很無聊的問題。同意bhuztez,Erlang無證腦殘粉 說的。

兩者的速度差很小。如果你要平凡操作的話,那還不如直接用C寫個擴展。

否則純屬自己創造問題,減低工作效率 


你這個有點讓納什踢足球然後看他舔腳的感覺……

python把事情給numpy的時候是要轉換數據的,反過來也是一樣

如果對數據處理過程時間的節約不足抵消轉換這些時間,那還是python自己解決比較好嘛_(:з」∠)_

話說題主你不妨試試numexpr→_→大數組跑起來飛快但是切片這種事一定不會比numpy快www

話說切片這活難道不是額外的trick一樣的功能么_(:з」∠)_


除了單元素訪問,我又測試了下數組切片的性能

Test1:

import numpy as np
mat = np.zeros(100).reshape(-1,5) #20*5的矩陣

a = mat
b = mat.reshape(-1,)
c = mat.tolist()

%timeit a[:,3]
%timeit b[3::5]
%timeit c[3::5]

我要獲取一個5*200矩陣中第4列的所有元素,這種操作挺常見的。三個操作效果是等價的,耗時分別是:(注意最後一個的單位)

100000 loops, best of 3: 2.18 μs per loop
1000000 loops, best of 3: 1.29 μs per loop
1000000 loops, best of 3: 332 ns per loop

還是list更快,比numpy同等操作快了三倍以上···另外numpy內部的切片性能差距也挺大

Test2:

元素數目加到1000

mat = np.zeros(1000).reshape(-1,5)

結果顯示速度差距變小了(list的操作耗時增加,numpy的兩種操作耗時甚至略有下降!)

100000 loops, best of 3: 2.16 μs per loop
1000000 loops, best of 3: 1.28 μs per loop
1000000 loops, best of 3: 442 ns per loop

Test3:

元素數目加到10000

mat = np.zeros(10000).reshape(-1,5)

結果顯示numpy穩如泰山,list耗時正式超過numpy···

100000 loops, best of 3: 2.16 μs per loop
1000000 loops, best of 3: 1.29 μs per loop
100000 loops, best of 3: 2.11 μs per loop

哎,Numpy的內部機制真是magic (°?°)

說句真心話,優化好麻煩···我難道是M?


推薦閱讀:

fMRI experiment Design:GLM引發的一些實驗設計要求
Dynamic Causal Modeling:確定性因果模型(上)
複雜數據處理(下):1816-2013年拉薩年平均氣溫變化分析

TAG:Python | 性能 | 科學計算 | 性能優化 | 數據處理 |