我希望能够计算一个大型的二维矩阵的滚动分位数,其维度为(1e6, 1e5),按列进行计算。由于需要执行此操作数千次,并且计算成本非常高,因此我正在寻找最快的方式。在实验中使用了窗口大小为1000和q值为0.1。
Numpy Strided:
Numba:
时间不太理想,理想情况下我希望能将速度提高10-50倍。如果您有任何建议如何加速它,我将不胜感激。也许有人有使用更低级别语言(Cython)或其他基于Numpy/Numba/Tensorflow的方法来加速的想法。谢谢!
import numpy as np
import pandas as pd
import multiprocessing as mp
from functools import partial
import numba as nb
X = np.random.random((10000,1000)) # Original array has dimensions of about (1e6, 1e5)
我的当前方法:
Pandas:%timeit:每次循环5.8秒±15.5毫秒
def pd_rolling_quantile(X, window, q):
return pd.DataFrame(X).rolling(window).quantile(quantile=q)
Numpy Strided:
%timeit: 2min 42s ± 3.29 s per loop
的翻译结果为:Numpy跨步:%timeit:每次循环2分42秒±3.29秒
。def strided_app(a, L, S):
nrows = ((a.size-L)//S)+1
n = a.strides[0]
return np.lib.stride_tricks.as_strided(a, shape=(nrows,L), strides=(S*n,n))
def np_1d(x, window, q):
return np.pad(np.percentile(strided_app(x, window, 1), q*100, axis=-1), (window-1, 0) , mode='constant')
def np_rolling_quantile(X, window, q):
results = []
for i in np.arange(X.shape[1]):
results.append(np_1d(X[:,i], window, q))
return np.column_stack(results)
多进程:%timeit:每次循环1.13秒±27.6毫秒
def mp_rolling_quantile(X, window, q):
pool = mp.Pool(processes=12)
results = pool.map(partial(pd_rolling_quantile, window=window, q=q), [X[:,i] for i in np.arange(X.shape[1])])
pool.close()
pool.join()
return np.column_stack(results)
Numba:
%timeit: 每次循环2分28秒±182毫秒
@nb.njit
def nb_1d(x, window, q):
out = np.zeros(x.shape[0])
for i in np.arange(x.shape[0]-window+1)+window:
out[i-1] = np.quantile(x[i-window:i], q=q)
return out
def nb_rolling_quantile(X, window, q):
results = []
for i in np.arange(X.shape[1]):
results.append(nb_1d(X[:,i], window, q))
return np.column_stack(results)
时间不太理想,理想情况下我希望能将速度提高10-50倍。如果您有任何建议如何加速它,我将不胜感激。也许有人有使用更低级别语言(Cython)或其他基于Numpy/Numba/Tensorflow的方法来加速的想法。谢谢!