2017-09-25 57 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