【问题标题】:Why doesn't my custom made linear regression model match sklearn?为什么我定制的线性回归模型与 sklearn 不匹配?
【发布时间】:2019-07-02 06:20:43
【问题描述】:

我正在尝试使用 Python 创建一个简单的线性模型,不使用任何库(numpy 除外)。这就是我所拥有的

import numpy as np

import pandas

np.random.seed(1)

alpha = 0.1

def h(x, w):
  return np.dot(w.T, x)

def cost(X, W, Y):
  totalCost = 0
  for i in range(47):
    diff = h(X[i], W) - Y[i]
    squared = diff * diff
    totalCost += squared

  return totalCost / 2

housing_data = np.loadtxt('Housing.csv', delimiter=',')

x1 = housing_data[:,0]
x2 = housing_data[:,1]
y = housing_data[:,2]

avgX1 = np.mean(x1)
stdX1 = np.std(x1)
normX1 = (x1 - avgX1) / stdX1
print('avgX1', avgX1)
print('stdX1', stdX1)

avgX2 = np.mean(x2)
stdX2 = np.std(x2)
normX2 = (x2 - avgX2) / stdX2

print('avgX2', avgX2)
print('stdX2', stdX2)

normalizedX = np.ones((47, 3))

normalizedX[:,1] = normX1
normalizedX[:,2] = normX2

np.savetxt('normalizedX.csv', normalizedX)

weights = np.ones((3,))

for boom in range(100):
  currentCost = cost(normalizedX, weights, y)
  if boom % 1 == 0:
    print(boom, 'iteration', weights[0], weights[1], weights[2])
    print('Cost', currentCost)

  for i in range(47):
    errorDiff = h(normalizedX[i], weights) - y[i]
    weights[0] = weights[0] - alpha * (errorDiff) * normalizedX[i][0]
    weights[1] = weights[1] - alpha * (errorDiff) * normalizedX[i][1]
    weights[2] = weights[2] - alpha * (errorDiff) * normalizedX[i][2]

print(weights)

predictedX = [1, (2100 - avgX1) / stdX1, (3 - avgX2) / stdX2]
firstPrediction = np.array(predictedX)
print('firstPrediction', firstPrediction)
firstPrediction = h(firstPrediction, weights)
print(firstPrediction)

首先,它收敛得非常快。仅经过 14 次迭代。其次,它给了我与sklearn 的线性回归不同的结果。作为参考,我的sklearn 代码是:

import numpy
import matplotlib.pyplot as plot
import pandas
import sklearn
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression

dataset = pandas.read_csv('Housing.csv', header=None)

x = dataset.iloc[:, :-1].values
y = dataset.iloc[:, 2].values

linearRegressor = LinearRegression()

xnorm = sklearn.preprocessing.scale(x)
scaleCoef = sklearn.preprocessing.StandardScaler().fit(x)
mean = scaleCoef.mean_
std = numpy.sqrt(scaleCoef.var_)
print('stf')
print(std)

stuff = linearRegressor.fit(xnorm, y)

predictedX = [[(2100 - mean[0]) / std[0], (3 - mean[1]) / std[1]]]
yPrediction = linearRegressor.predict(predictedX)
print('predictedX', predictedX)
print('predict', yPrediction)


print(stuff.coef_, stuff.intercept_)

我的自定义模型预测 y 的值为 337,000,sklearn 预测为 355,000。我的数据是 47 行,看起来像

2104,3,3.999e+05
1600,3,3.299e+05
2400,3,3.69e+05
1416,2,2.32e+05
3000,4,5.399e+05
1985,4,2.999e+05
1534,3,3.149e+05

完整数据可在https://github.com/shamoons/linear-logistic-regression/blob/master/Housing.csv获取

我假设 (a) 我的梯度下降回归在某种程度上是错误的,或者 (b) 我没有正确使用 sklearn

对于给定输入,2 不会预测相同输出的任何其他原因?

【问题讨论】:

  • 您能提供一份您的数据吗?
  • 我添加了完整数据集的链接
  • 我认为线性回归器是基于 scipy.linalg.lstsq 的,它使用 lapack gelsd 驱动程序(svd 解决最小二乘问题)。我认为因为您使用的是梯度下降而不是相同的算法,它们可能会导致不同的权重,从而导致不同的预测。
  • @plasmon360 我可以让 scikit 使用梯度下降吗?
  • @Shamoon 我认为你可以使用随机梯度回归器 (scikit-learn.org/stable/modules/generated/…) 它类似于梯度下降,但计算梯度的方式不同。

标签: python numpy machine-learning scikit-learn gradient-descent


【解决方案1】:

我认为您在梯度下降中缺少 1/m 项(其中 m 是 y 的大小)。包含 1/m 项后,我似乎得到了一个类似于您的 sklearn 代码的预测值。

见下文

....
weights = np.ones((3,))

m = y.size
for boom in range(100):
  currentCost = cost(normalizedX, weights, y)
  if boom % 1 == 0:
    print(boom, 'iteration', weights[0], weights[1], weights[2])
    print('Cost', currentCost)

  for i in range(47):
    errorDiff = h(normalizedX[i], weights) - y[i]
    weights[0] = weights[0] - alpha *(1/m)* (errorDiff) * normalizedX[i][0]
    weights[1] = weights[1] - alpha *(1/m)*  (errorDiff) * normalizedX[i][1]
    weights[2] = weights[2] - alpha *(1/m)* (errorDiff) * normalizedX[i][2]

...

这给出了第一个预测是 355242。

这与线性回归模型非常吻合,即使它不做梯度下降。

我还在 sklearn 中尝试了 sgdregressor(使用随机梯度下降),它似乎也获得了接近线性回归模型和您的模型的值。看下面的代码

import numpy
import matplotlib.pyplot as plot
import pandas
import sklearn
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression, SGDRegressor

dataset = pandas.read_csv('Housing.csv', header=None)

x = dataset.iloc[:, :-1].values
y = dataset.iloc[:, 2].values

sgdRegressor = SGDRegressor(penalty='none', learning_rate='constant', eta0=0.1, max_iter=1000, tol = 1E-6)

xnorm = sklearn.preprocessing.scale(x)
scaleCoef = sklearn.preprocessing.StandardScaler().fit(x)
mean = scaleCoef.mean_
std = numpy.sqrt(scaleCoef.var_)
print('stf')
print(std)

yPrediction = []
predictedX = [[(2100 - mean[0]) / std[0], (3 - mean[1]) / std[1]]]
print('predictedX', predictedX)
for trials in range(10):
    stuff = sgdRegressor.fit(xnorm, y)
    yPrediction.extend(sgdRegressor.predict(predictedX))
print('predict', np.mean(yPrediction))

结果

predict 355533.10119985335

【讨论】:

猜你喜欢
  • 2021-06-11
  • 2021-01-04
  • 2018-08-02
  • 2019-07-03
  • 1970-01-01
  • 2018-05-16
  • 2021-08-09
  • 2021-02-18
  • 2019-03-03
相关资源
最近更新 更多