2017-09-25 82 views
4

我有一個矩陣X有7000列和38000行的東西。因此它是一個形狀爲(38000, 7000)numpy arrayScikitLearn迴歸:設計矩陣X對於迴歸太大。我該怎麼辦?

我實例化的模型

model = RidgeCV(alphas = (0.001,0.01, 0.1, 1) 

再裝它

model.fit(X, y) 

其中y是響應向量其是numpy的陣列形狀(38000,)

通過運行我得到一個Memory Error

我該如何解決這個問題?

我的想法

我首先想到的是分割矩陣X 「水平」。通過這個,我的意思是我將X分成兩列,即具有相同列數的矩陣(從而保留所有特徵),但行數更少。那麼,我是否每次都爲這些子矩陣擬合模型?但恐怕這實在是不等同於整個矩陣擬合..

任何想法?

+0

我建議使用具有'partial_fit'參數的迴歸算法,如['SGDRegressor'](http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDRegressor.html# sklearn.linear_model.SGDRegressor)。然後你可以以分塊的方式輸入你的矩陣。你必須手動完成你的簡歷。 –

+0

因此,用CV進行嶺迴歸時不存在「部分擬合」的實現? –

回答

6

這是一個衆所周知的問題,可以使用核心外學習解決。用google搜索這個詞,你會發現幾種方法來解決這個問題。

針對您的特定問題,您首先要創建一個生成矩陣的行(或幾個)並使用算法的partial_fit方法的生成器。

scikit-learn的標準算法實際上是對解決方案的精確計算,如sklearn.linear_model.LinearRegressionsklearn.linear_model.LinearRegression.RidgeCV。其他方法是基於一批學習和有partial_fit方法,如sklearn.linear_model.SGDRegressor,允許只適合一小批。這是你在找什麼。

該過程是:使用發生器產生一個小批量,應用partial_fit方法,從內存中刪除小批量並獲得一個新的。

但是,由於這種方法是隨機的,並且取決於數據的順序和權重的初始化,與標準迴歸方法給出的解決方案相反,該解決方案可以適應內存中的所有數據。我不會進入細節,但看看梯度下降優化,以瞭解它是如何工作的(http://ruder.io/optimizing-gradient-descent/

3

這在我看來並不是很大規模,你可能不需要使用out-of-core在這裏學習(雖然我不知道你有多少內存)。

使用外的核心辦法不需要的時候,你將爲此付出代價(不健壯無重調整)!

知道你的特徵是稀疏的還是密集的,這可能會產生巨大的差異(因爲大多數求解器可以利用稀疏數據!)。

有些事情要在這裏說:

  • RidgeCV使用,可能因爲這個原因,一些問題調校交叉驗證方法,對控制求解基本
    • 沒有參數的情況並不少見使用問題調整的CV方法時,高效的熱啓動可以幫助過程(性能)
  • 當手動進行CV時,所有工具都可用在sklearn,你可以選擇不同的solvers
    • 那些在方法方面和特點

求解器有很大的不同:{ '汽車', 'SVD', '喬萊斯基', 'LSQR', 'sparse_cg', '下垂', '傳奇'}

規劃求解的計算程序使用:

「汽車選擇自動根據數據的類型的解算器。

'svd'使用X的奇異值分解來計算嶺係數。對於奇異矩陣比「膽小」更穩定。

'cholesky'使用標準的scipy.linalg.solve函數來獲得封閉形式的解決方案。

'sparse_cg'使用scipy.sparse.linalg.cg中的共軛梯度解算器。作爲一種迭代算法,這種求解器對於大規模數據(可能性設置tol和max_iter)比'cholesky'更合適。

'lsqr'使用專用正則化最小二乘例程scipy.sparse.linalg.lsqr。這是最快的,但可能不會在舊的scipy版本中可用。它也使用迭代過程。

'sag'使用隨機平均漸變下降,'saga'使用其改進的無偏版本SAGA。兩種方法都使用迭代過程,並且在n_samples和n_features都很大時,它們通常比其他求解器更快。請注意,'sag'和'saga'快速收斂只能保證大小相同的特徵。您可以使用sklearn.preprocessing中的縮放器預處理數據。

所有最後五個解算器都支持密集數據和稀疏數據。但是,當fit_intercept爲True時,只有'sag'和'saga'支持稀疏輸入。

所以我強烈建議嘗試:sparse_cg也許lsqr具有手動CV在一起。如果這是行得通的(對我來說完美無缺),我期望的是,這種方法更穩定/更強大(與使用SGD的核心外方法相比),而且您不需要調整其參數,是一個巨大的優勢。

當然,人們總是可以使用sagsgd,但收斂理論是基於一些關於參數調整的強烈假設。在非常大規模的環境中,這兩個是可行的候選人(因爲其他人不會工作),但在這裏我沒有看到太多merrit(再次:我不知道你有多少內存)。如果上述方法不起作用,請在sgd之前嘗試saga並遵守規則(標準化+參數調整)。 (編輯:下垂是非常糟糕的爲我的測試數據!)

例子:

from sklearn.datasets import make_regression 
from sklearn.linear_model import Ridge 
from time import perf_counter 

X, y, = make_regression(n_samples=38000, n_features=7000, n_informative=500, 
         bias=-2.0, noise=0.1, random_state=0) 

print(type(X)) # dense!!! if your data is sparse; use that fact! 

clf = Ridge(alpha=1.0, solver="lsqr") 
start = perf_counter() 
clf.fit(X, y) 
end = perf_counter() 
print('LSQR: used secs: ', end-start) 

輸出:

LSQR: used secs: 8.489622474064486 

所以即使在密集的情況下,這並不難優化(並使用〜6-8 GB的內存)。

雖然我會小心地指出Ridge模型和以下基於SGD的Ridge模型之間的等價關係(小心哪個變量是正則化的一部分;太懶得檢查了),這裏只是一個演示它有多難是調整SGD。用一粒鹽(也許不要評估絕對分數;但方差取決於參數):

備註:這是一個較小的例子!使用你原來的例子中,沒有新元的辦法將得到收斂無需手動設置下學習率eta_0

局部代碼(如內部啓發式不能爲你做的!):

X, y, = make_regression(n_samples=3800, n_features=700, n_informative=500, 
         noise=0.1, random_state=0) 

print(type(X)) # dense!!! if your data is sparse; use that fact! 

clf = Ridge(alpha=1.0, solver="lsqr", fit_intercept=False) 
start = perf_counter() 
clf.fit(X, y) 
end = perf_counter() 
print('LSQR: used secs: ', end-start) 
print('train-score: ', clf.score(X, y)) 

clf = Ridge(alpha=1.0, solver="sparse_cg", fit_intercept=False) 
start = perf_counter() 
clf.fit(X, y) 
end = perf_counter() 
print('sparse_cg: used secs: ', end-start) 
print('train-score: ', clf.score(X, y)) 

clf = SGDRegressor(loss='squared_loss', penalty='l2', alpha=1., fit_intercept=False, 
        random_state=0) 
start = perf_counter() 
clf.fit(X, y) 
end = perf_counter() 
print('SGD: used secs: ', end-start) 
print('train-score: ', clf.score(X, y)) 

clf = SGDRegressor(loss='squared_loss', penalty='l2', alpha=1., fit_intercept=False, 
        random_state=0, average=True) 
start = perf_counter() 
clf.fit(X, y) 
end = perf_counter() 
print('SGD: used secs: ', end-start) 
print('train-score: ', clf.score(X, y)) 

clf = SGDRegressor(loss='squared_loss', penalty='l2', alpha=1., fit_intercept=False, 
        random_state=0, learning_rate="constant", eta0=0.001) 
start = perf_counter() 
clf.fit(X, y) 
end = perf_counter() 
print('SGD: used secs: ', end-start) 
print('train-score: ', clf.score(X, y)) 

clf = SGDRegressor(loss='squared_loss', penalty='l2', alpha=1., fit_intercept=False, 
        random_state=0, n_iter=50, average=True) 
start = perf_counter() 
clf.fit(X, y) 
end = perf_counter() 
print('SGD: used secs: ', end-start) 
print('train-score: ', clf.score(X, y)) 

輸出:

LSQR: used secs: 0.08252486090450709 
train-score: 0.999999907282 
sparse_cg: used secs: 0.13668818702548152 
train-score: 0.999999181151 
SGD: used secs: 0.04154542095705427 
train-score: 0.743448766459 
SGD: used secs: 0.05300238587407993 
train-score: 0.774611911034 
SGD: used secs: 0.038653031605587 
train-score: 0.733585661919 
SGD: used secs: 0.46313909066321507 
train-score: 0.776444474871 

另外:打算用於partial_fit/out-of-memory方法時,調諧的mini_batches尺寸也需要做(在上述演示被忽略 - >純SGD - >一次一個樣品) !再說一遍:這並不容易!

+0

IMO應該是被接受的答案。這些是一些重要的細節,可能會大大改善您的結果。 – charlesreid1