线性回归(机器学习4)

实验目的

梯度下降法是一个最优化算法,通常也称为最速下降法。最速下降法是求解无约束优化问题最简单和最古老的方法之一,虽然现已不具有实用性,但是许多有效算法都是以它为基础进行改进和修正而得到的。最速下降法是用负梯度方向为搜索方向的,最速下降法越接近目标值,步长越小,前进越慢。
线性回归是利用数理统计中回归分析,来确定两种或两种以上变量间相互依赖的定量关系的一种统计分析方法,运用十分广泛。其表达形式为y = w'*x+e,e为误差服从均值为0的正态分布。[1]
回归分析中,只包括一个自变量和一个因变量,且二者的关系可用一条直线近似表示,这种回归分析称为一元线性回归分析。如果回归分析中包括两个或两个以上的自变量,且因变量和自变量之间是线性关系,则称为多元线性回归分析。
本次实验将验证梯度下降法可以求解线性回归的参数。

实验环境

本次实验,使用的程序语言为Python3.5,依赖的工具包为:

import matplotlib.pyplot as plt
import csv
import numpy as np
import pandas as pd
from mpl_toolkits.mplot3d import Axes3D

实验内容及步骤

  • 画出样本分布图;
  • 画出线性回归假设模型;
  • 画出成本函数收敛曲线
  • 使用梯度下降法更新参数
    在详细了解梯度下降的算法之前,我们先看看相关的一些概念。
    步长(Learning rate):步长决定了在梯度下降迭代的过程中,每一步沿梯度负方向前进的长度。用上面下山的例子,步长就是在当前这一步所在位置沿着最陡峭最易下山的位置走的那一步的长度。
    特征(feature):指的是样本中输入部分,比如样本(x0,y0),(x1,y1),则样本特征为x,样本输出为y。
    假设函数(hypothesis function):在监督学习中,为了拟合输入样本,而使用的假设函数,记为hθ(x)。
    损失函数(loss function):为了评估模型拟合的好坏,通常用损失函数来度量拟合的程度。损失函数极小化,意味着拟合程度最好,对应的模型参数即为最优参数。在线性回归中,损失函数通常为样本输出和假设函数的差取平方。
    预测值:

    误差:

    优化目标:

    参数更新:

    线性回归(机器学习4)_第1张图片

实验结果及分析

对数据进行了归一化处理。
对1维数据,迭代了300次0.02步长,500次0.01步长。最终结果如图:


线性回归(机器学习4)_第2张图片

线性回归(机器学习4)_第3张图片


对2维数据,迭代了700次0.01步长。最终结果如图:


线性回归(机器学习4)_第4张图片

线性回归(机器学习4)_第5张图片

如何调优?步长,初始参数,归一化。
方法变种:批量梯度下降,随机梯度下降,小批量。在每次选取样本的数量上有区别。
横向比较:梯度下降法和最小二乘法相比,梯度下降法需要选择步长,而最小二乘法不需要。梯度下降法是迭代求解,最小二乘法是计算解析解。如果样本量不算很大,且存在解析解,最小二乘法比起梯度下降法要有优势,计算速度很快。但是如果样本量很大,用最小二乘法由于需要求一个超级大的逆矩阵,这时就很难或者很慢才能求解解析解了,使用迭代的梯度下降法比较有优势。梯度下降法和牛顿法/拟牛顿法相比,两者都是迭代求解,不过梯度下降法是梯度求解,而牛顿法/拟牛顿法是用二阶的海森矩阵的逆矩阵或伪逆矩阵求解。相对而言,使用牛顿法/拟牛顿法收敛更快。但是每次迭代的时间比梯度下降法长。

总结

通过这次实验,我验证了经典优化算法。体会到了这些优化方法的巧妙,加深了对梯度下降法的理解。锻炼了编程实践的能力。更加坚定了我在未来的学习道路上求真笃行的态度。

程序

import scipy.io as sio
import numpy as np
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import KFold
import matplotlib.pyplot as plt
def predict(theta,x):
    '''
    theta:(d,1)
    x:(n,d)
    '''
    x=x.reshape((-1,1))
    return x.dot(theta).reshape((-1,1))
def const_error(h,y):
    return h-y
# 均方误差
# h:pred_y
def cost(h,y,con):
    return (np.mean(con**2))/2
def grad(x,con):
    return np.mean(con*x,axis=0,keepdims=True).transpose()
matfn='shuju.mat'
data=sio.loadmat(matfn)
print()
XY,epsilon=data['shuju'],data['epsilon'].ravel()[0]
gamma=0.01
epoch=10000
epsilon=1e-8
# np.savetxt('parameters.txt',[epsilon,gamma])
# np.save('data.npy',XY)
# print(type(XY),epsilon)
np.random.seed(2)
np.random.shuffle(XY)
X,Y=XY[:,:1],XY[:,1:]
min_max_scaler=MinMaxScaler()
X,Y=list(map(min_max_scaler.fit_transform,[X,Y]))
kfold=KFold(5)
thetas=[]#每一次的参数
for j,(train_index,test_index) in enumerate(kfold.split(X)):
    train_x,test_x,train_y,test_y=X[train_index],X[test_index],Y[train_index],Y[test_index]
    sc = []  # 训练集误差
    vc = []  # 交叉集预测误差
    theta = np.random.randn()#每次都要随机初始化
    this_time_con=100000#损失
    # if j!=3:
    #     continue
    for i in range(epoch):
        h = predict(theta, train_x)
        con = const_error(h, train_y)
        g = grad(train_x, con)
        pre_y = predict(theta, test_x)
        if gamma>=500:
            gamma*=0.95
        theta = theta - gamma * g#更新公式
        #存一下损失
        valdation_cost=cost(pre_y, test_y, const_error(pre_y, test_y))
        sc.append(cost(h, train_y, con))
        vc.append(valdation_cost)
        if abs(this_time_con-valdation_cost)<=epsilon:
            break
        else:
            this_time_con = valdation_cost
    plt.plot(np.arange(len(sc)), np.array(sc), label="training_cost")
    plt.legend()
    plt.plot(np.arange(len(vc)), np.array(vc), label="validating_cost")
    plt.legend()
    plt.xlabel("epoch")
    plt.ylabel("cost")
    plt.title(str(j)+'time_cost.png')
    # print(i,valdation_cost)
    plt.text(i,valdation_cost,'val_cost:\n(%d,%.3f)'%(i,valdation_cost),fontsize=8)
    # plt.show()
    plt.savefig(str(j)+'time_cost.png')
    plt.clf()
    thetas.append(theta.reshape(-1)[0])
    plt.scatter(X, Y, marker='x')
    plt.grid()
    x = np.arange(-0.2, 1.2, 0.001)
    y = predict(theta, x)
    plt.plot(x, y)
    plt.title("%dtime_predict" % (j))
    # plt.savefig("%dtime_predict" % (j))
    plt.clf()

import json
json.dump(thetas,open('thetas.json','w'))

'''
我们可以看到第3次出现了损失上升的情况,这是学习率过大导致的
所以我们在400次迭代时,降低学习率
'''

你可能感兴趣的:(线性回归(机器学习4))