2017-06-01 74 views
7

我試圖改善func功能的性能,我發現是如何產生的aX列表一個簡單的改變提高了性能相當多:爲什麼處理隨機列表比處理有序列表快得多?

import timeit 
import numpy as np 

def func(a, b): 
    return [_ for _ in a if _ not in b] 

Na, Nb = 10000, 5000 
b = list(np.random.randint(1000, size=Nb)) 

# Ordered list of Na integers 
a1 = [_ for _ in range(Na)] 
# Random list of Na integers 
a2 = list(np.random.randint(Na, size=Na)) 
# Ordered list of Na integers generated with numpy 
a3 = list(np.arange(Na)) 

start_time = timeit.default_timer() 
ab1 = func(a1, b) 
abt1 = timeit.default_timer() - start_time 
print("Time ab1", abt1) 

start_time = timeit.default_timer() 
ab2 = func(a2, b) 
abt2 = timeit.default_timer() - start_time 
print("Time ab2", abt2) 

start_time = timeit.default_timer() 
ab3 = func(a3, b) 
abt3 = timeit.default_timer() - start_time 
print("Time ab3", abt3) 

print("Ratio 1/2:", abt1/abt2) 
print("Ratio 1/3:", abt1/abt3) 

在Python 2.7.13這導致:

('Time ab1', 5.296088933944702) 
('Time ab2', 1.5520200729370117) 
('Time ab3', 1.5581469535827637) 
('Ratio 1/2:', 3.412384302428827) 
('Ratio 1/3:', 3.3989662667998095) 

在Python 3.5.2的差甚至更大:

Time ab1 6.758207322000089 
Time ab2 1.5693355060011527 
Time ab3 1.5148192759988888 
Ratio 1/2: 4.306413317073784 
Ratio 1/3: 4.461395117608107 

我需要處理的有序列表整數(即:a1a3),所以我的問題是:

爲什麼隨機列表處理,從而速度遠遠超過了有序列表numpy產生的?

+0

這可能是一個愚蠢的問題,但是在你完成了它的處理之後,你不能*重新排序*或者*排列* list * **嗎? –

+2

這是一個公平的測試?列表'a1'中的最大值將是10000(列表的長度),其中列表'a2'中的最大值將是1000,因爲它將是0到1000之間的隨機數,因此將'a1 = [ _用於範圍(Na)]''用'a1 = [_ // 10用於範圍(Na)]'給出4.6的比率仍然不確定爲什麼它更快。或者我誤解了這一點。 –

+0

@ Alessi42提出了一個有效的觀點。我將編輯這個問題來解決這個問題。謝謝! – Gabriel

回答

7

ba2a3名單是NumPy的標量的列表,而你a1名單是普通的Python整數列表。將NumPy標量與普通Python標量進行比較需要額外的類型檢查和強制,因此需要比較NumPy標量和普通Python標量的func(a1, b)測試執行速度最慢。

如果您使b成爲Python整數列表(通過調用tolist method而不是list函數),則時間差是相反的。

您可能要考慮使用Python set s或NumPy的set-like operations來執行您的任務。

1

正如討論的here numpy數組比python列表快得多。這就是爲什麼numpy數組看起來更快,因爲當您調用list()函數時仍然使用numpy數組。

使用numpy的.tolist()函數轉換NumPy的陣列到正規Python對象一路下跌(如user2357112指出)和性能上的差異消失了,請參閱:

import timeit 
import numpy as np 

def func(a, b): 
    return [_ for _ in a if _ not in b] 

Na, Nb = 10000, 5000 
b = list(np.random.randint(Na, size=Nb)) # len: 5000, max: 9999 

# Ordered list of Na integers 
a1 = [_ for _ in range(Na)] # len: 10000, max: 9999 
# Random list of Na integers 
a2 = np.random.randint(Na, size=Na).tolist() # len: 10000, max: 9999 
# Ordered list of Na integers generated with numpy 
a3 = np.arange(Na).tolist() 

start_time = timeit.default_timer() 
ab1 = func(a1, b) 
abt1 = timeit.default_timer() - start_time 
print("Time ab1", abt1) 

start_time = timeit.default_timer() 
ab2 = func(a2, b) 
abt2 = timeit.default_timer() - start_time 
print("Time ab2", abt2) 

start_time = timeit.default_timer() 
ab3 = func(a3, b) 
abt3 = timeit.default_timer() - start_time 
print("Time ab3", abt3) 

print("Ratio 1/2:", abt1/abt2) 
print("Ratio 1/3:", abt1/abt3) 

#Time ab1 4.622085004015502 
#Time ab2 4.598610720638726 
#Time ab3 4.63976530848255 
#Ratio 1/2: 1.005104646773301 
#Ratio 1/3: 0.9961893968139456 

希望這回答了你的第一個問題!

+3

你可以給一個'這是爲什麼numpy數組看起來更快,因爲當你調用list()函數時你還在使用numpy數組嗎? –

+0

我現在已經包含了'ndarray的文檔。tolist()'但我似乎無法找到一個爲什麼'list()'不這樣做的引用我認爲如果他們爲它添加了一個函數,它不能在默認情況下執行 –

+0

'list'確實建立一個清單。 'tolist'將NumPy數組轉換爲常規Python對象,構建多維數組的嵌套列表並將所有標量轉換爲普通Python標量。 – user2357112