首页 > 编程笔记 > Python笔记 阅读:13

梯度下降法详解(附带实例)

梯度下降法(Gradient Descent,GD)的代价函数是误差平方和(SSE),它与 OLS 所用的代价函数相同,为:

其中, 为预测值:


OLS 回归可以理解为没有单位阶跃函数的 Adaline,这样就可以得到连续的目标值,而不是分类标签 -1 和 1。

【实例】用普通最小二乘法估计线性回归的参数,从而使样本点的垂直距离(残差或误差)之和最小化。
from sklearn.preprocessing import StandardScaler
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] #显示中文
plt.rcParams['axes.unicode_minus']=False

df=pd.read_csv('housing.data',
                     header=None,
                     sep='\s+')
df.columns=['CRIM', 'ZN', 'INDUS', 'CHAS',
                 'NOX', 'R M', 'AGE', 'DIS', 'RAD',
                 'TAX', 'PTRATIO', 'B', 'LSTAT', 'M EDV']
print(df.head())                              #显示住房数据集
运行程序,输出如下:
      CRIM      ZN    INDUS   CHAS     NOX      R M  AGE    DIS    RAD   TAX   \
0   0.00632    18.0   2.31      0     0.538   6.575  65.2  4.0900   1   296.0
1   0.02731     0.0   7.07      0     0.469   6.421  78.9  4.9671   2   242.0
2   0.02729     0.0   7.07      0     0.469   7.185  61.1  4.9671   2   242.0
3   0.03237     0.0   2.18      0     0.458   6.998  45.8  6.0622   3   222.0
4   0.06905     0.0   2.18      0     0.458   7.147  54.2  6.0622   3   222.0
    PTRATIO      B       LSTAT     M EDV
0     15.3     396.90     4.98      24.0
1     17.8     396.90     9.14      21.6
2     17.8     392.83     4.03      34.7
3     18.7     394.63     2.94      33.4
4     18.7     396.90     5.33      36.2

#一个线性回归模型
class LinearRegressionGD(object):
   def__init__(self, eta=0.001, n_iter=20):
       self.eta=eta
       self.n_iter=n_iter
          
   def fit(self, X, y):
       self.w_=np.zeros(1+X.shape[1])
       self.cost_=[]
   for i in range(self.n_iter):
       output=self.net_input(X)
       errors=(y-output)
       self.w_[1:]+=    self.eta * X.T.dot(errors)
       self.w_[0]+=self.eta * errors.sum()
       cost=(errors * * 2).sum()/2.0
       self.cost_.append(cost)
   return self
          
def net_input(self, X):
   return np.dot(X, self.w_[1:])+self.w_[0]
          
def predict(self, X):
   return self.net_input(X)
为了观察 LinearRegressionGD 回归器的具体实现,用住房数据的 RM(房间数)变量作为解释变量,训练可以预测 MEDV(房价)的模型。此外通过标准化变量以确保梯度下降法算法具有更好的收敛性。
X=df[['R M']].values
y=df['M EDV'].values

sc_x=StandardScaler()
sc_y=StandardScaler()
X_std=   sc_x.fit_transform(X)
#sklearn的大多数转换器期望数据存储在二维阵列
y_std=   sc_y.fit_transform(y[:, np.newaxis]).flatten()
lr=LinearRegressionGD()
lr.fit(X_std, y_std)

绘制使用梯度下降的优化算法时,以训练集迭代次数作为成本函数成本,检查算法是否收敛到了最低成本。
plt.plot(range(1, lr.n_iter+1), lr.cost_)
plt.ylabel('SSE')
plt.xlabel('Epoch')
plt.show()     #效果如图 4 所示

图 4 算法的收敛效果

通过可视化手段,观察线性回归与训练数据的拟合程度。为此,定义简单的辅助函数绘制训练样本的散点图并添加回归线:
#观察线性回归与训练数据的拟合程度
def lin_regplot(X, y, model):
    #s:指定散点图点的大小, 默认为20, 通过传入新的变量, 实现气泡图的绘制
    #c:指定散点图点的颜色, 默认为蓝色
    #edgecolors:设置散点边界线的颜色
    plt.scatter(X, y, c='steelblue', edgecolor='white', s=70)
    plt.plot(X, model.predict(X), color='black', lw=2)
    return
#用lin_regplot函数来绘制房间数目与房价之间的关系, 如图7-8所示
lin_regplot(X_std, y_std, lr)
plt.xlabel('平均房间数[R M](标准化)')
plt.ylabel('价格为1000美元[M EDV](标准化)')
plt.show()

图 5 房间数目与房价之间的关系

如图 5 所示,线性回归反映了房价随房间数目增加的基本趋势。但是数据显示,在许多情况下,房间数目并不能很好地解释房价。

在某些应用中,将预测结果变量以原始缩放进行报告也很重要。可以直接调用 StandardScaler 的 inverse_transform 方法,把对价格预测的结果恢复到以价格为 1000 美元的坐标轴上:
#把价格的预测结果恢复到以价格为1000美元的坐标轴
num_rooms_std=sc_x.transform(np.array([[5.0]]))
#有5个房间的房屋价格
price_std=lr.predict(num_rooms_std)
print("价格为1000美元:%.3f"% sc_y.inverse_transform(price_std))
价格为1000美元:10.840

根据模型计算,这样的房屋价格为 10 840 美元。另外,如果处理标准化变量,从技术角度来说,不需要更新截距的权重,因为在这些情况下,y 轴的截距是 0。可以通过打印权重来快速确认这一点:
print('Slope:%.3f'%lr.w_[1])
print('Intercept:%.3f'%lr.w_[0])
运行程序,输出如下:

Slope:0.695
Intercept:-0.000

相关文章