岭回归

一、满秩矩阵
设A是n阶矩阵, 若r(A) = n, 则称A为满秩矩阵。但满秩不局限于n阶矩阵。
若矩阵秩等于行数,称为行满秩;若矩阵秩等于列数,称为列满秩。既是行满秩又是列满秩则为n阶矩阵即n阶方阵。行满秩矩阵就是行向量线性无关,列满秩矩阵就是列向量线性无关;所以如果是方阵,行满秩矩阵与列满秩矩阵是等价的。·
二、中心化和标准化
这里先介绍下数据的中心化和标准化,在回归问题和一些机器学习算法中通常要对原始数据进行中心化和标准化处理,也就是需要将数据的均值调整到0,标准差调整为1, 计算过程很简单就是将所有数据减去平均值后再除以标准差:
在这里插入图片描述
这样调整后的均值:
在这里插入图片描述
调整后的标准差:
在这里插入图片描述
之所以需要进行中心化其实就是个平移过程,将所有数据的中心平移到原点。而标准化则是使得所有数据的不同特征都有相同的尺度Scale, 这样在使用梯度下降法以及其他方法优化的时候不同特征参数的影响程度就会一致了。
三、岭回归
标准最小二乘法优化问题:
在这里插入图片描述
也可以通过矩阵表示:
在这里插入图片描述

得到回归系数为:
在这里插入图片描述
若给定数据集X,如果XTX的逆存在,可以使用常规的线性回归方法。但是,

(1)数据样本数比特征数少的情况,矩阵的逆不能直接计算;

(2)即使样本数多于特征数,若特征高度相关,XTX的逆依然无法计算。

此时,可以考虑岭回归。
在最小二乘估计的基础上,岭回归增加了一项,称为岭回归估计:
在这里插入图片描述
此时求解的式子变成了:
在这里插入图片描述
其中新增的最后一项称为惩罚函数。
在这里插入图片描述

进一步,这个问题又可以转化成:
在这里插入图片描述
相当于在最小二乘法的基础上添加了对参数β的约束。岭参数λ接近0时,岭回归变为最小二乘法;岭参数λ变大时,参数β趋近于0。
三、岭回归代码

为了使用岭回归和缩减技术,首先需要对特征做标准化处理。因为,我们需要使每个维度特征具有相同的重要性。本文使用的标准化处理比较简单,就是将所有特征都减去各自的均值并除以方差。
代码很简单,只需要稍做修改,其中,λ为模型的参数。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

import numpy as np


def loadDataSet(fileName):
"""
加载数据
:param fileName: 文件名
:return: 
 xArr - x数据集
yArr - y数据集
"""
numFeat = len(open(fileName).readline().split('\t')) - 1
xArr = [] 
yArr = []
f = open(fileName)
for line in f.readlines():
    lineArr =[]
    curLine = line.strip().split('\t')
    for i in range(numFeat):
        lineArr.append(float(curLine[i]))
    xArr.append(lineArr)
    yArr.append(float(curLine[-1]))
return xArr, yArr
def ridgeRegres(xMat, yMat, lam = 0.2):
"""
 岭回归
:param xMat: x数据集
:param yMat: y数据集
:param lam: 缩减系数
:return: 
  ws - 回归系数
"""
xTx = xMat.T * xMat
denom = xTx + np.eye(np.shape(xMat)[1]) * lam
if np.linalg.det(denom) == 0.0:
    print("矩阵为奇异矩阵,不能转置")
    return
ws = denom.I * (xMat.T * yMat)
return ws
  • mean() 函数定义:
    numpy.mean(a, axis, dtype, out,keepdims )

mean()函数功能:求取均值
经常操作的参数为axis,以m * n矩阵举例:

axis 不设置值,对 mn 个数求均值,返回一个实数
axis = 0:压缩行,对各列求均值,返回 1
n 矩阵
axis =1 :压缩列,对各行求均值,返回 m *1 矩阵

  • mean在数组中的操作
    在这里插入图片描述在这里插入图片描述在这里插入图片描述

  • mean在矩阵中的操作
    在这里插入图片描述

  • var()函数:
    def var(a, axis=None, dtype=None, out=None, ddof=0, keepdims=np._NoValue):
    对于二维矩阵,axis的值可以是0也可以是1,其中axis=0表示按列求平均,当axis=1表示按行求平均,未给出axis则表示将所有元素加起来求平均。
    在这里插入图片描述
    数据集ex1.txt
    在这里插入图片描述根据数据集求得的ws如下:
    在这里插入图片描述
    所以在岭回归中初始回归系数矩阵写成: wMat = np.zeros((numTestPts, np.shape(xMat)[1]))

     def ridgeTest(xArr, yArr):
     """
     岭回归测试函数
    :param xArr: x数据集
     :param yArr: y数据集
     :return: 
      wMat - 回归系数矩阵
     """
     xMat = np.mat(xArr); yMat = np.mat(yArr).T
     #数据标准化
     yMean = np.mean(yMat, axis = 0)                        #求每列均值
     yMat = yMat - yMean                                    #数据减去均值
     xMeans = np.mean(xMat, axis = 0)                    #求每列均值
     xVar = np.var(xMat, axis = 0)                        #求每列方差
     xMat = (xMat - xMeans) / xVar                        #数据减去均值除以方差实现标准化
     numTestPts = 30                                        #30个不同的lambda测试
     wMat = np.zeros((numTestPts, np.shape(xMat)[1]))    #初始回归系数矩阵
     for i in range(numTestPts):                            #改变lambda计算回归系数
         ws = ridgeRegres(xMat, yMat, np.exp(i - 10))    #lambda以e的指数变化,最初是一个非常小的数,
         wMat[i, :] = ws.T                                 #计算回归系数矩阵
     return wMat
    

四、前向逐步线性回归
前向逐步线性回归算法属于一种贪心算法,即每一步都尽可能减少误差。我们计算回归系数,不再是通过公式计算,而是通过每次微调各个回归系数,然后计算预测误差。那个使误差最小的一组回归系数,就是我们需要的最佳回归系数。

import numpy as np
def loadDataSet(fileName):
    """
    加载数据
    :param fileName: 文件名
    :return:
     xArr - x数据集
    yArr - y数据集
    """
    numFeat = len(open(fileName).readline().split('\t')) - 1
    xArr = []
    yArr = []
    fr = open(fileName)
    for line in fr.readlines():
        lineArr =[]
        curLine = line.strip().split('\t')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        xArr.append(lineArr)
        yArr.append(float(curLine[-1]))
    return xArr, yArr


def regularize(xMat, yMat):
    """
    函数说明:数据标准化
    Parameters:
        xMat - x数据集
        yMat - y数据集
    Returns:
        inxMat - 标准化后的x数据集
        inyMat - 标准化后的y数据集
    """
    inxMat = xMat.copy()  # 数据拷贝
    inyMat = yMat.copy()
    yMean = np.mean(yMat, 0)  # 行与行操作,求均值
    inyMat = yMat - yMean  # 数据减去均值
    inMeans = np.mean(inxMat, 0)  # 行与行操作,求均值
    inVar = np.var(inxMat, 0)  # 行与行操作,求方差
    inxMat = (inxMat - inMeans) / inVar  # 数据减去均值除以方差实现标准化
    return inxMat, inyMat


def rssError(yArr, yHatArr):
    """
    计算平方误差
    Parameters:yArr - 预测值
    Parameters:yHatArr - 真实值

    Returns:

    """
    return ((yArr - yHatArr) ** 2).sum()

	def stageWise(xArr, yArr, eps=0.01, numIt=100):
    """
    前向逐步线性回归
    Parameters:xArr - x输入数据
    Parameters:yArr - y预测数据
    Parameters:eps - 每次迭代需要调整的步长
    Parameters:numIt - 迭代次数
    Returns:

    """
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T  # 数据集
    xMat, yMat = regularize(xMat, yMat)  # 数据标准化
    m, n = np.shape(xMat)
    returnMat = np.zeros((numIt, n))  # 初始化numIt次迭代的回归系数矩阵
    ws = np.zeros((n, 1))  # 初始化回归系数矩阵
    wsTest = ws.copy()
    wsMax = ws.copy()
    for i in range(numIt):  # 迭代numIt次
        print(ws.T)                                                                    #打印当前回归系数矩阵
        lowestError = float('inf');  # 正无穷
        for j in range(n):  # 遍历每个特征的回归系数
            for sign in [-1, 1]:
                wsTest = ws.copy()
                wsTest[j] += eps * sign  # 微调回归系数
                yTest = xMat * wsTest  # 计算预测值
                rssE = rssError(yMat.A, yTest.A)  # 计算平方误差
                if rssE < lowestError:  # 如果误差更小,则更新当前的最佳回归系数
                    lowestError = rssE
                    wsMax = wsTest
        ws = wsMax.copy()
        returnMat[i, :] = ws.T  # 记录numIt次迭代的回归系数矩阵
    return returnMat

在这里插入图片描述可以看到,有些系数从始至终都是约为0的,这说明它们不对目标造成任何影响,也就是说这些特征很可能是不需要的。逐步线性回归算法的优点在于它可以帮助人们理解有的模型并做出改进。当构建了一个模型后,可以运行该算法找出重要的特征,这样就有可能及时停止对那些不重要特征的收集。
五、预测乐高玩具套件的价格
使用岭回归,通过交叉验证,找到使误差最小的λ对应的回归系数。
在这里插入图片描述numpy中np.nonzero()函数可参考:https://blog.csdn.net/u013698770/article/details/54632047

def crossValidation(xArr, yArr, numVal=10):                                                                        
    """                                                                                                            
    函数说明:交叉验证岭回归                                                                                                   
    Parameters:                                                                                                    
        xArr - x数据集                                                                                                
        yArr - y数据集                                                                                                
        numVal - 交叉验证次数                                                                                            
    Returns:                                                                                                       
        wMat - 回归系数矩阵                                                                                              
                                                                                                                   
    """                                                                                                            
    m = len(yArr)  # 统计样本个数                                                                                        
    indexList = list(range(m))  # 生成索引值列表                                                                          
    errorMat = np.zeros((numVal, 30))  # create error mat 30columns numVal rows                                    
    for i in range(numVal):  # 交叉验证numVal次                                                                         
        trainX = [];                                                                                               
        trainY = []  # 训练集                                                                                         
        testX = [];                                                                                                
        testY = []  # 测试集                                                                                          
        random.shuffle(indexList)  # 打乱次序                                                                          
        for j in range(m):  # 划分数据集:90%训练集,10%测试集                                                                  
            if j < m * 0.9:                                                                                        
                trainX.append(xArr[indexList[j]])                                                                  
                trainY.append(yArr[indexList[j]])                                                                  
            else:                                                                                                  
                testX.append(xArr[indexList[j]])                                                                   
                testY.append(yArr[indexList[j]])                                                                   
        wMat = ridgeTest(trainX, trainY)  # 获得30个不同lambda下的岭回归系数                                                   
        for k in range(30):  # 遍历所有的岭回归系数                                                                          
            matTestX = np.mat(testX);                                                                              
            matTrainX = np.mat(trainX)  # 测试集                                                                      
            meanTrain = np.mean(matTrainX, 0)  # 测试集均值                                                             
            varTrain = np.var(matTrainX, 0)  # 测试集方差                                                               
            matTestX = (matTestX - meanTrain) / varTrain  # 测试集标准化                                                 
            yEst = matTestX * np.mat(wMat[k, :]).T + np.mean(trainY)  # 根据ws预测y值                                   
            errorMat[i, k] = rssError(yEst.T.A, np.array(testY))  # 统计误差                                           
    meanErrors = np.mean(errorMat, 0)  # 计算每次交叉验证的平均误差                                                             
    minMean = float(min(meanErrors))  # 找到最小误差                                                                     
    bestWeights = wMat[np.nonzero(meanErrors == minMean)]  # 找到最佳回归系数                                              
    xMat = np.mat(xArr);                                                                                           
    yMat = np.mat(yArr).T                                                                                          
    meanX = np.mean(xMat, 0);                                                                                      
    varX = np.var(xMat, 0)                                                                                         
    unReg = bestWeights / varX  # 数据经过标准化,因此需要还原                                                                   
    print('%f%+f*年份%+f*部件数量%+f*是否为全新%+f*原价' % (                                                                    
    (-1 * np.sum(np.multiply(meanX, unReg)) + np.mean(yMat)), unReg[0, 0], unReg[0, 1], unReg[0, 2], unReg[0, 3])) 

更多内容可参考:https://www.jianshu.com/p/9d14c3c34a0c

  • 13
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值