我在一段代碼中遇到了瓶頸,這會破壞我的代碼的性能。我重新撰寫了該部分,但是,在計時之后,情況并沒有改善。
問題如下。給定一個固定長度的整數串列串列
data = [[1,2,3], [3,2,1], [8,1,0], [1,3,4]]
我需要將每個子串列的索引附加到一個單獨的串列中,次數與其在給定列索引處的串列值一樣多。資料中的每一列都有一個單獨的串列。
例如,對于上述資料,由于子串列具有三列,因此將有三個結果串列。
有 4 個子串列,因此我們希望數字 0-3 出現在每個最終串列中。
我們期望從以上資料生成以下三個串列
[[0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3],
[0, 0, 1, 1, 2, 3, 3, 3],
[0, 0, 0, 1, 3, 3, 3, 3]]
我有兩種方法可以做到這一點:
processed_data = list([] for _ in range(len(data[0])))
for n in range(len(data)):
sub_list = data[n]
for k, proc_list in enumerate(processed_data):
for _ in range(sub_list[k]):
proc_list.append(n)
processed_data = []
for i, col in enumerate(zip(*data)):
processed_data.append([j for j,count in enumerate(col) for _ in range(count)])
該data串列的平均大小約為 100,000。
有什么辦法可以加快速度嗎?
uj5u.com熱心網友回復:
除非您能夠調整輸出格式(見下文),否則您無法提高演算法的計算復雜度。換句話說,您最多只能將速度提高一個適度的百分比(并且該百分比將與輸入的大小無關)。
我沒有看到任何明顯的實施問題。我的一個想法append()是通過預先分配輸出矩陣來擺脫大量呼叫和逐漸串列擴展所產生的開銷,但@juanpa.arrivillaga 在他們的評論中建議,這append()實際上在 CPython 上非常優化。如果您使用另一個解釋器,您可以嘗試一下:您知道 column 的輸出串列的長度c將等于column中所有輸入數字的總和c。因此,您可以使用 預先分配每個輸出串列[0] * sum_of_input_values_at_column_c,然后執行proc_list[i] = n而不是proc_list.append(n)(并手動增加i)。但是,這確實需要對輸入進行兩次傳遞,因此它實際上可能不是改進 - 您的問題非常占用記憶體,因為其核心計算非常簡單。
你不能提高計算復雜度的原因是它已經是最優的:任何演算法都需要花時間來生成它的輸出,所以輸出的大小是演算法可能多快的下限。在您的情況下,輸出的大小等于輸入矩陣中值的總和(當您依賴輸入值本身而不是輸入值的數量時,通常認為這是不好的)。這就是你的演算法花費的迭代次數,所以它是最優的。但是,如果此函式的輸出將駐留在記憶體中以供另一個函式使用(而不是寫入檔案),并且您可以在該函式中進行一些調整,則可以改為輸出生成器矩陣,sub_list[k]的發生n。然后,演算法的復雜性與輸入矩陣的大小成正比(但消耗輸出仍將花費與生成完整輸出所需的時間相同的時間)。
uj5u.com熱心網友回復:
也許 itertools 可以通過最大限度地減少回圈內的 python 代碼量來讓你更快地完成這項作業:
data = [[1,2,3], [3,2,1], [8,1,0], [1,3,4]]
from itertools import chain,repeat,starmap
result = [ list(chain.from_iterable(starmap(repeat,r)))
for r in map(enumerate,zip(*data)) ]
print(result)
[[0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3],
[0, 0, 1, 1, 2, 3, 3, 3],
[0, 0, 0, 1, 3, 3, 3, 3]]
如果您以與結果行相同的順序處理輸出,您可以將其轉換為生成器并直接在主行程中使用它:
iResult = ( chain.from_iterable(starmap(repeat,r))
for r in map(enumerate,zip(*data)) )
for iRow in iResult: # iRow is also an iterator
for resultItem in iRow:
# Perform your item processing here
print(resultItem, end=" ")
print()
0 1 1 1 2 2 2 2 2 2 2 2 3
0 0 1 1 2 3 3 3
0 0 0 1 3 3 3 3
這將完全避免創建和存盤索引串列(即將瓶頸降低到零)。但這僅當您按順序處理結果時
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/390775.html
