如果這個問題看起來很基本,我真誠地道歉。
鑒于:
>>> import numpy as np
>>> import time
>>> A = np.random.rand( int(1e5), int(5e4) ) # large numpy array
目標:
>>> bt=time.time(); B=np.argsort(A,axis=1);et=time.time();print(f"Took {(et-bt):.2f} s")
但是,計算索引陣列需要很長時間:
# Took 316.90 s
題:
有沒有其他時間有效的方法來做到這一點?
干杯,
uj5u.com熱心網友回復:
默認情況下,輸入陣列A的形狀為(100_000, 50_000)并包含np.float64值。這意味著您只需要8 * 100_000 * 50_000 / 1024**3 = 37.2 Gio這個陣列的記憶體。您可能還需要相同數量的輸出矩陣空間B(它應該包含型別為 的專案np.int64)。這意味著您需要一臺至少具有 74.4 Gio 的機器,更不用說作業系統 (OS) 和運行軟體所需的空間(因此可能至少為 80 Gio)。如果您沒有這樣的記憶體空間,那么您的作業系統將使用您的存盤設備作為交換記憶體,這會慢得多。
假設你有這樣一個可用的記憶體空間,這樣的計算是非常昂貴的。這主要是由于填充陣列時的頁面錯誤B,以及B相當大的事實以及Numpy的默認實作按順序進行計算。您可以使用并行 Numba 代碼和較小的輸出來加快計算速度。下面是一個例子:
import numba as nb
@nb.njit('int32[:,::1](float64[:,::1])', parallel=True)
def fastSort(a):
b = np.empty(a.shape, dtype=np.int32)
for i in nb.prange(a.shape[0]):
b[i,:] = np.argsort(a[i,:])
return b
請注意,Numba 的實作argsort效率低于 Numpy,但如果目標機器具有 mny 內核和良好的記憶體帶寬,則并行版本應該快得多。
以下是我的 6 核機器在大小矩陣上的結果(10_000, 50_000)(小 10 倍,因為我沒有 80 Gio 的 RAM):
Original implementation: 28.14 s
Sequential Numba: 38.70 s
Parallel Numba: 6.79 s
因此,所得解決方案的速度提高了 4.1 倍。
請注意,在這種特定情況下,您甚至可以使用uint16專案的型別,B因為每行的大小小于2**16 = 65536。這可能不會明顯更快,但它應該節省一些額外的記憶體。由此產生的所需記憶體將為 46.5 Gio。您可以進一步減少使用該np.float32型別所需的記憶體量(通常以損失準確性為代價)。
如果您想進一步縮短執行時間,那么您需要argsort使用 C 或 C 等低級語言為您的特定需求實作更快的實作。但是請注意,如果您不是使用這種語言的有經驗的程式員或不熟悉低級優化,那么擊敗 Numpy 絕非易事。如果您對這樣的解決方案感興趣,一個好的開始可能是實作基數排序。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/333539.html
標籤:Python 麻木 表现 numpy-ndarray
下一篇:逐行讀取檔案的最快方法是什么?
