线性回归实现总是比 sklearn 表现差
Posted
技术标签:
【中文标题】线性回归实现总是比 sklearn 表现差【英文标题】:Linear regression implementation always performs worse than sklearn 【发布时间】:2014-03-05 17:29:42 【问题描述】:我在 python 中使用梯度下降实现了线性回归。为了了解它的表现如何,我将它与 scikit-learn 的 LinearRegression() 类进行了比较。出于某种原因,sklearn 的平均 MSE 总是优于我的程序 3(我正在使用 Boston Housing 数据集进行测试)。我知道我目前没有进行梯度检查来检查收敛,但我允许多次迭代并且将学习率设置得足够低以使其应该收敛。我的学习算法实现中是否有任何明显的错误?这是我的代码:
import numpy as np
from sklearn.linear_model import LinearRegression
def getWeights(x):
lenWeights = len(x[1,:]);
weights = np.random.rand(lenWeights)
bias = np.random.random();
return weights,bias
def train(x,y,weights,bias,maxIter):
converged = False;
iterations = 1;
m = len(x);
alpha = 0.001;
while not converged:
for i in range(len(x)):
# Dot product of weights and training sample
hypothesis = np.dot(x[i,:], weights) + bias;
# Calculate gradient
error = hypothesis - y[i];
grad = (alpha * 1/m) * ( error * x[i,:] );
# Update weights and bias
weights = weights - grad;
bias = bias - alpha * error;
iterations = iterations + 1;
if iterations > maxIter:
converged = True;
break
return weights, bias
def predict(x, weights, bias):
return np.dot(x,weights) + bias
if __name__ == '__main__':
data = np.loadtxt('housing.txt');
x = data[:,:-1];
y = data[:,-1];
for i in range(len(x[1,:])):
x[:,i] = ( (x[:,i] - np.min(x[:,i])) / (np.max(x[:,i]) - np.min(x[:,i])) );
initialWeights,initialBias = getWeights(x);
weights,bias = train(x,y,initialWeights,initialBias,55000);
pred = predict(x, weights,bias);
MSE = np.mean(abs(pred - y));
print "This Program MSE: " + str(MSE)
sklearnModel = LinearRegression();
sklearnModel = sklearnModel.fit(x,y);
sklearnModel = sklearnModel.predict(x);
skMSE = np.mean(abs(sklearnModel - y));
print "Sklearn MSE: " + str(skMSE)
【问题讨论】:
【参考方案1】:首先,确保您正在计算正确的目标函数值。线性回归目标应该是.5*np.mean((pred-y)**2)
,而不是np.mean(abs(pred - y))
。
您实际上是在运行随机梯度下降 (SGD) 算法(对单个示例运行梯度迭代),这应该与“梯度下降”区分开来。
SGD 是一种很好的学习方法,但却是一种糟糕的优化方法——它可能需要多次迭代才能收敛到最小的经验误差 (http://leon.bottou.org/publications/pdf/nips-2007.pdf)。
要使 SGD 收敛,必须限制学习率。通常,使用代码中的变量将学习率设置为基本学习率除以迭代次数,例如alpha/(iterations+1)
。
您还可以在渐变中包含多个 1/m
,这通常不会用于 SGD 更新。
要测试您的 SGD 实施,而不是评估您训练时使用的数据集上的错误,请将数据集拆分为训练集和测试集,并在使用这两种方法进行训练后评估此测试集上的错误。训练/测试集拆分将允许您将算法的性能估计为学习算法(估计预期误差)而不是优化算法(最小化经验误差)。
【讨论】:
感谢您的精彩回答!我没有意识到我实际上是在做 SGD。正如您所说,添加 1/m 的倍数会让人失望;该算法现在的性能与 scikit-learn 一样好。【参考方案2】:尝试增加您的迭代值。这应该允许您的算法有希望地收敛到更接近全局最小值的值。请记住,您没有使用 l-bfgs,它可以比普通梯度下降甚至 SGD 更快地接近收敛。
还可以尝试使用正态方程作为另一种进行线性回归的方法。
http://eli.thegreenplace.net/2014/derivation-of-the-normal-equation-for-linear-regression/.
【讨论】:
以上是关于线性回归实现总是比 sklearn 表现差的主要内容,如果未能解决你的问题,请参考以下文章