Python实现线性回归3,局部加权线性回归,lasso回归,岭回归

接上篇

5.局部加权线性回归

局部加权线性回归(LWLR),在该算法中,我们给待预测点附近的每个点赋予一定的权重,在这个自己上基于最小均方差进行普通的回归,每次预测均需要先选取出对应数据子集。该算法接触回归系数w的形式如下:
普通线性回归: w ^ = ( X T X ) 1 X T y \hat{w} = (X^TX)^{-1}·X^Ty
加权(weight)线性回归: w ^ = ( X T W X ) 1 X T W y \hat{w} = (X^TWX)^{-1}·X^TWy ,w是一个矩阵,用来给每个数据点赋予权重。
LWLR使用“核”对附近的点赋予更高的权重。核的类型可以自由选择,最常用的就是高斯核,其对应的权重: w ( i , i ) = e x p ( x i x 2 2 k 2 ) w(i,i) = exp(\frac{|x^i-x|^2}{-2·k^2}) (与支持向量机中的核一致)。w是只含有对角线元素的矩阵w,点x与x(i)越近,则w(i,i)机会越大,也就是说距离中心点越近的权重越大,对拟合曲线的影响也就越大,所以也有了局部加权这一名词。公式中的k为超参数,需要自行指定,他决定了对附近的点赋予多大的权重。
LWLR方法对待预测的每个点赋予一定的权重,在这样的一个子集上基于最小均方差来进行普通的回归。因此,会增加计算量,它对每个点做预测时都必须使用整个数据集,实际预测结果一般。
代码如下(代码参考自《机器学习实战》第8章):

def linearRegLwlr(x,y,k=1.0):
    #局部加权线性回归,k为高斯核函数的参数
    # \hat{w} = (X^TWX)^{-1}·X^TWy
    xMat = np.mat(x)
    yMat = np.mat(y).T  # 传入数据是1*m的矩阵,将其转置成m*1维矩阵
    m = np.shape(x)[0]  # 数据条数
    yHat = np.zeros(m)  # 初始化预测值y矩阵
    
    for i in range(m):  #遍历x,从1到m,使用解析解求每一个yhat
        weights = np.mat(np.eye((m)))     # 需要根据每条数据,计算权重,每条的权重都不相同
        for j in range(m):                # 遍历所有数据求解一条数据对应的权重
            diffMat = x[i] - xMat[j,:]    
            weights[j,j] = np.exp(diffMat*diffMat.T/(-2.0*k**2)) # 高斯核函数
        xTx = xMat.T * (weights * xMat)   # x转置*x
        if np.linalg.det(xTx) == 0.0:     # 判断矩阵是否可逆,行列式是否等于0
            print("This matrix is singular, cannot do inverse")
        ws = xTx.I * (xMat.T * (weights * yMat)) # 求得这一条数据的解析解
        yHat[i]=x[i] * ws                 # x[i]为1,将值赋值给yHat矩阵
    return yHat
   
    print('')
    print('3.5、局部加权线性回归,linearRegLwlr函数,无theta解析式!')
    print('局部加权线性回归拟合结果图,使用第一列TV数据展示!')
    yHat=linearRegLwlr(x,y.T,k=1)
    # 绘图
    xMat = np.mat(x)
    srtIndex = xMat[:,0].argsort(axis=0)
    xSort = xMat[srtIndex][:,0,:]
    # 绘制散点图
    fig = plt.figure(1)
    ax = fig.add_subplot(111)
    ax.plot(xSort[:,0],yHat[srtIndex])
    ax.scatter(xMat[:,0].flatten().A[0],np.mat(yHat).flatten().A[0],s=2,c='red')    #必须是数组的形式
    plt.show()

6.岭回归

岭回归实际上相当于有约束条件情况的最小二乘法回归,即回归系数为: w ^ = ( X T X + λ I ) 1 X T y \hat{w} = (X^TX+λI)^{-1}·X^Ty ,另一种写法: m i n   w X w y 2 2 + α w 2 2 \underset{w}{min\,} {{|| X w - y||_2}^2 + \alpha {||w||_2}^2} 。惩罚λ的引入能够减少不重要的参数,从而更好滴理解数据。参数λ的选择,需要将原训练数据分成训练数据和测试数据,在训练数据上训练回归系数,然后在测试数据上测试性能,通过选取不同的λ来重复上述过程,最终选取使得预测误差最小的λ。
岭回归缺陷:
1.主要靠目测选择岭参数
2.计算岭参数时,各种方法结果差异较大
所以一般认为,岭迹图只能看多重共线性,却很难做变量筛选。
代码如下(代码参考自《机器学习实战》第8章):

def linearRegRidge(x,y,k=1.0,lam=0.2):
    xMat = np.mat(x)
    yMat = np.mat(y)
    yMat = yMat - np.mean(y,0)     # 数据归一化
    xMat = (xMat - np.mean(xMat,0))/np.var(xMat,0) # 数据归一化,因为lambda*I在数值很大时,系数w平方会非常大
    
    numTestPts = 30  # N组lanba值
    wMat = np.zeros((numTestPts,np.shape(xMat)[1]))# 30组lanba值
    for i in range(numTestPts): # 求每组的w系数
        #ws = ridgeRegres(xMat,yMat,np.exp(i-10))
        # i=0
        print(i,np.exp(i-10))
        lam=np.exp(i-10) # 使用指数级递增,效果更有效
        xTx = xMat.T*xMat # x转置*x
        denom = xTx + np.eye(np.shape(xMat)[1])*lam # x转置*x 加上单位阵
        if np.linalg.det(denom) == 0.0: # 判断矩阵是否可逆,行列式是否等于0
            print("This matrix is singular, cannot do inverse")
            #return
        ws = denom.I * (np.dot(xMat.T,yMat)) # 求得一组w系数
        wMat[i,:]=ws.T
    
    print('30组wMat,不同lam下参数情况:',wMat)
    return wMat
    
    theta6=linearRegRidge(x,y)
    print('')
    print('3.6、岭回归,linearRegRidge函数,多组theta解析式!',theta6)

7.lasso回归

lasso回归通过构造一个一阶惩罚函数获得一个精炼的模型;通过最终确定一些指标(变量)癿系数为零(岭回归估计系数等于0癿机会微乎其微,造成筛选变量困难),解释力很强。
擅长处理具有多重共线性的数据,筛选变量,与岭回归一样是有偏估计。lasso回归则是与岭回归略有不同,使用了L1正则: m i n   w X w y 2 2 + α w 2 \underset{w}{min\,} {{|| X w - y||_2}^2 + \alpha {||w||_2}}
lasso回归代码如下:

待补充,!!!∑(゚Д゚ノ)ノ,有点复杂,以后再弄了,先去弄逻辑回归了!!

以上算法完整代码如下

# -*- coding: utf-8 -*-
"""
 @Time    : 2018/10/24 10:23
 @Author  : hanzi5
 @Email   : **@163.com
 @File    : linear_regression.py
 @Software: PyCharm
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression

def linearRegLwlr(x,y,k=1.0):
    #局部加权线性回归,k为高斯核函数的参数
    # \hat{w} = (X^TWX)^{-1}·X^TWy
    xMat = np.mat(x)
    yMat = np.mat(y).T  # 传入数据是1*m的矩阵,将其转职成m*1维矩阵
    m = np.shape(x)[0]  # 数据条数
    yHat = np.zeros(m)  # 初始化预测值y矩阵
    
    for i in range(m):  #遍历x,从1到m,使用解析解求每一个yhat
        weights = np.mat(np.eye((m)))     # 需要根据每条数据,计算权重,每条的权重都不相同
        for j in range(m):                # 遍历所有数据求解一条数据对应的权重
            diffMat = x[i] - xMat[j,:]    
            weights[j,j] = np.exp(diffMat*diffMat.T/(-2.0*k**2)) # 高斯核函数
        xTx = xMat.T * (weights * xMat)   # 求解析解
        if np.linalg.det(xTx) == 0.0:     # 判断矩阵是否可逆,行列式是否等于0
            print("This matrix is singular, cannot do inverse")
        ws = xTx.I * (xMat.T * (weights * yMat)) # 求得这一条数据的解析解
        yHat[i]=x[i] * ws                 # x[i]为1,将值赋值给yHat矩阵
    return yHat
def linearRegRidge(x,y,k=1.0,lam=0.2):
    xMat = np.mat(x)
    yMat = np.mat(y)
    yMat = yMat - np.mean(y,0)     # 数据归一化
    xMat = (xMat - np.mean(xMat,0))/np.var(xMat,0) # 数据归一化,因为lambda*I在数值很大时,系数w平方会非常大
    
    numTestPts = 30  # N组lanba值
    wMat = np.zeros((numTestPts,np.shape(xMat)[1]))# 30组lanba值
    for i in range(numTestPts): # 求每组的w系数
        #ws = ridgeRegres(xMat,yMat,np.exp(i-10))
        # i=0
        print(i,np.exp(i-10))
        lam=np.exp(i-10) # 使用指数级递增,效果更有效
        xTx = xMat.T*xMat # x转置*x
        denom = xTx + np.eye(np.shape(xMat)[1])*lam # x转置*x 加上单位阵
        if np.linalg.det(denom) == 0.0: # 判断矩阵是否可逆,行列式是否等于0
            print("This matrix is singular, cannot do inverse")
            #return
        ws = denom.I * (np.dot(xMat.T,yMat)) # 求得一组w系数
        wMat[i,:]=ws.T
    
    print('30组wMat,不同lam下参数情况:',wMat)
    return wMat
       
if __name__ == "__main__":
    path = 'D:/python_data/8.Advertising.csv'
    data = pd.read_csv(path)  # TV、Radio、Newspaper、Sales
    #data_matrix = data.as_matrix(columns=['TV', 'Radio', 'Newspaper', 'Sales'])  # 转换数据类型
    data_array = data.values[:,1:]  # 转换数据类型,去除第一列序号列
    x = data_array[:, :-1] #去除y对应列的数据,其他列作为x
    y = data_array[:, -1].reshape((-1,1))
    
    print('')
    print('3.5、局部加权线性回归,linearRegLwlr函数,无theta解析式!')
    print('局部加权线性回归拟合结果图,使用第一列TV数据展示!')
    yHat=linearRegLwlr(x,y.T,k=1)
    # 绘图
    xMat = np.mat(x)
    srtIndex = xMat[:,0].argsort(axis=0)
    xSort = xMat[srtIndex][:,0,:]
    # 绘制散点图
    fig = plt.figure(1)
    ax = fig.add_subplot(111)
    ax.plot(xSort[:,0],yHat[srtIndex])
    ax.scatter(xMat[:,0].flatten().A[0],np.mat(yHat).flatten().A[0],s=2,c='red')    #必须是数组的形式
    plt.show()

    theta6=linearRegRidge(x,y)
    print('')
    print('3.6、岭回归,linearRegRidge函数,多组theta解析式!',theta6)

数据见以下链接,复制到txt文档中,另存为CSV格式即可。
数据

参考资料:
1、python实现线性回归
2、机器学习:线性回归与Python代码实现
3、python实现简单线性回归
4、Machine-Learning-With-Python
5、《机器学习》西瓜书,周志华著
6、机器学习视频,邹博
7、 斯坦福大学公开课 :机器学习课程
8、马同学高等数学 如何直观形象的理解方向导数与梯度以及它们之间的关系?
9、【机器学习】线性回归的梯度下降法
10、机器学习 线性回归 梯度下降 python实现
11、《机器学习实战》Peter Harrington著
12、Lasso Regression 作者:Duanxx

猜你喜欢

转载自blog.csdn.net/weixin_43383558/article/details/83340222