我在Python中使用梯度下降法实现了线性回归。为了评估其表现,我将其与scikit-learn的LinearRegression()类进行了比较。不知为何,sklearn的平均均方误差(MSE)总是比我的程序低3(我使用波士顿房价数据集进行测试)。我知道目前我没有进行梯度检查来确认是否收敛,但我允许进行多次迭代,并且将学习率设置得足够低,应该可以收敛。我的学习算法实现中是否有明显的错误?这是我的代码:
import numpy as npfrom sklearn.linear_model import LinearRegressiondef getWeights(x): lenWeights = len(x[1,:]); weights = np.random.rand(lenWeights) bias = np.random.random(); return weights,biasdef 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, biasdef predict(x, weights, bias): return np.dot(x,weights) + biasif __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)
回答:
首先,确保你计算的目标函数值是正确的。线性回归的目标函数应该是.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实现,而不是在你训练过的数据集上评估误差,应该将数据集分成训练集和测试集,并在训练后用这两种方法在测试集上评估误差。训练/测试集的分割将允许你估计你的算法作为学习算法的表现(估计期望误差),而不是作为优化算法(最小化经验误差)。