• 机器学习实战第8章预测数值型数据:回归


    1.简单的线性回归

    假定输入数据存放在矩阵X中,而回归系数存放在向量W中,则对于给定的数据X1,预测结果将会是

                    

    这里的向量都默认为列向量

    现在的问题是手里有一些x和对应的y数据,怎样才能找到W呢?一个常用的方法是找到使误差最小的W,这里的误差是指预测y值与真实y值之间的差值,使用该误差的简单累加将使得正差值和负差值相互抵消,所以我们采用平方误差。

    平方误差可以写做:

                    

    用矩阵表示可以写成

                    

    使用上式对w进行求导:

                    

    具体可参考https://blog.csdn.net/nomadlx53/article/details/50849941

    令上述导数为0,即可得

                    

    2. 局部加权线性回归

      线性回归的一个问题是有可能出现欠拟合现象,因为它求的是具有小均方误差的无偏估计。显而易见,如果模型欠拟合将不能取得好的预测效果。所以有些方法允许在估计中引入一 些偏差,从而降低预测的均方误差。

      其中的一个方法是局部加权线性回归(Locally Weighted Linear Regression,LWLR)。在该方法中,我们给待预测点附近的每个点赋予一定的权重。与kNN一样,这种算法每次预测均需要事先选取出对应的数据子集。该算法解除回归系数W的形式如下:

                          

      LWLR使用"核"(与支持向量机中的核类似)来对附近的点赋予更高的权重。核的类型可以自由选择,最常用的核就是高斯核,高斯核对应的权重如下:

                        

      其中k需要用户设定,它决定了对附近的点赋予多大的权重,控制衰减速度

    下面是代码 

    from numpy import mat,linalg,corrcoef,shape,eye,exp,zeros
    import matplotlib.pyplot as plt
    import numpy as np
    
    def loadDataSet(fileName):
        numFeat = len(open(fileName).readline().split('\t')) - 1
        dataMat = []; labelMat = []
        fr = open(fileName)
        for line in fr.readlines():
            lineArr = []
            curLine = line.strip().split('\t')
            for i in range(numFeat):
                lineArr.append(float(curLine[i]))
            dataMat.append(lineArr)
            labelMat.append(float(curLine[-1]))
        return dataMat, labelMat
    
    
    """
        函数说明:线性回归
        ParameterS:
            xArr - x数据集
            yArr - y数据集
        Returns:
            ws  - 回归系数
    """
    def standRegres(xArr, yArr):
        xMat = mat(xArr); yMat = mat(yArr).T
        xTx = xMat.T*xMat
        # linalg.det()计算行列式,若为0,则不可逆
        if linalg.det(xTx) == 0.0:
            print("This matrix is singular, cannot do inverse")
            return
        #回归系数ws = (X^TX)^-1X^Ty
        ws = xTx.I * (xMat.T * yMat)
        return ws
    
    
    def plotStandRegres(xMat, yMat, ws):
        fig = plt.figure()
        ax = fig.add_subplot(111)
        xCopy = xMat.copy()
        yHat = xCopy * ws
        # flatten()函数Return a copy of the array collapsed into one dimension.
        # .A将矩阵转化为数组
        ax.scatter(xMat[:, 1].flatten().A[0], yMat.T[:, 0].flatten().A[0])
        ax.plot(xCopy[:, 1], yHat,'r')
        plt.show()
    
    
    """
        函数说明:局部加权线性回归
        Parameters:
            testPoint - 测试点,xArr -  x数据集,yArr - y数据集,
            k   - 高斯核的参数,自定义,控制衰减速度
        Returns:
            测试点y值
    """
    def lwlr(testPoint, xArr, yArr, k=1.0):
        xMat = mat(xArr)    # m * n
        yMat = mat(yArr).T  # m * 1
        m = shape(xMat)[0]
        weights = mat(eye(m))   #生成对角矩阵,对角线上元素全为1,其他为0
        for j in range(m):
            diffMat = testPoint - xMat[j,:]
            weights[j,j] = exp(diffMat * diffMat.T / (-2.0*k**2))   #权重随着距离的增加,以指数级衰减
        xTx = xMat.T * (weights * xMat)
        if linalg.det(xTx) == 0.0:
            print("This matrix is singular, cannot do inverse")
            return
        ws = xTx.I * (xMat.T * (weights * yMat))
        return testPoint * ws
    
    
    """
        函数说明:局部加权线性回归测试函数
        Parameters:
            testPoint - 测试x数据集,xArr -  x数据集,yArr - y数据集,
            k - 高斯核的参数,自定义,控制衰减速度
        Returns:
            yHat - 预测y数据集 
    """
    def lwlrTest(testArr, xArr, yArr, k=1.0):
        m = shape(testArr)[0]
        yHat = zeros(m)
        for i in range(m):
            yHat[i] = lwlr(testArr[i], xArr, yArr, k)
        return yHat
    
    
    def plotLwlr(xMat, yMat):
        plt.rcParams['font.sans-serif'] = ['SimHei']
        plt.rcParams['axes.unicode_minus'] = False
        strInd = xMat[:,1].argsort(0)   #对x进行排序,并返回排序下标
        xSort = xMat[strInd][:,0,:]
        yHat1 = lwlrTest(xArr, xArr, yArr, 1.0)
        yHat2 = lwlrTest(xArr, xArr, yArr, 0.01)
        yHat3 = lwlrTest(xArr, xArr, yArr, 0.003)
        fig, axs = plt.subplots(nrows=3, ncols=1, sharex=False, sharey=False, figsize=(10, 8))
        axs[0].plot(xSort[:, 1], yHat1[strInd], c='red')
        axs[1].plot(xSort[:, 1], yHat2[strInd], c='red')
        axs[2].plot(xSort[:, 1], yHat3[strInd], c='red')
        axs[0].scatter(xMat[:, 1].flatten().A[0], yMat.T[:, 0].flatten().A[0])
        axs[1].scatter(xMat[:, 1].flatten().A[0], yMat.T[:, 0].flatten().A[0])
        axs[2].scatter(xMat[:, 1].flatten().A[0], yMat.T[:, 0].flatten().A[0])
        #设置标题,x轴y轴label
        axs0_title_text = axs[0].set_title(u'局部加权回归曲线,k=1.0')
        axs1_title_text = axs[1].set_title(u'局部加权回归曲线,k=0.01')
        axs2_title_text = axs[2].set_title(u'局部加权回归曲线,k=0.003')
        plt.setp(axs0_title_text, size=8, weight='bold', color='red')
        plt.setp(axs1_title_text, size=8, weight='bold', color='red')
        plt.setp(axs2_title_text, size=8, weight='bold', color='red')
        plt.xlabel('X')
        plt.ylabel('Y')
        plt.show()
    
    
    if __name__ == '__main__':
        xArr, yArr = loadDataSet('ex0.txt')
        ws = standRegres(xArr, yArr)
        xMat = mat(xArr)
        yMat = mat(yArr)
        yHat = xMat * ws  # 预测y值
        plotStandRegres(xMat, yMat, ws)
        #计算相关系数
        print(corrcoef(yHat.T, yMat))
        plotLwlr(xMat, yMat)
    

    简单线性回归的运行结果:

         

    相关系数:

          

      

     局部加权回归:

      

    从图中可以看出在三种k的取值中,k=0.01的结果相对更好一些,k=0.003时会出现过拟合的情况。

    局部加权回归存在一个问题:增加了计算量,每次必须在整个数据集上运行

    3.示例:预测鲍鱼的年龄

    """
        函数说明:计算误差
    """
    def rssError(yArr,yHatArr): #yArr and yHatArr both need to be arrays
        return ((yArr-yHatArr)**2).sum()
    
    if __name__ == '__main__':
        xArr, yArr = regression.loadDataSet('abalone.txt')
        print('训练集与测试集相同:局部加权线性回归,核k的大小对预测的影响:')
        yHat01 = regression.lwlrTest(xArr[0:99], xArr[0:99], yArr[0:99], 0.1)
        yHat1 = regression.lwlrTest(xArr[0:99], xArr[0:99], yArr[0:99], 1)
        yHat10 = regression.lwlrTest(xArr[0:99], xArr[0:99], yArr[0:99], 10)
        print('k=0.1时,误差大小为:',rssError(yArr[0:99], yHat01.T))
        print('k=1时,误差大小为:',rssError(yArr[0:99], yHat1.T))
        print('k=10.1时,误差大小为:',rssError(yArr[0:99], yHat10.T))
        print('')
        print('训练集与测试集不同:局部加权线性回归,核k的大小对预测的影响:')
        yHat01 = regression.lwlrTest(xArr[100:199], xArr[0:99], yArr[0:99], 0.1)
        yHat1 = regression.lwlrTest(xArr[100:199], xArr[0:99], yArr[0:99], 1)
        yHat10 = regression.lwlrTest(xArr[100:199], xArr[0:99], yArr[0:99], 10)
        print('k=0.1时,误差大小为:',rssError(yArr[100:199], yHat01.T))
        print('k=1时,误差大小为:',rssError(yArr[100:199], yHat1.T))
        print('k=10时,误差大小为:',rssError(yArr[100:199], yHat10.T))
        print('')
        print('训练集与测试集不同:简单的线性归:')
        ws = regression.standRegres(xArr[0:99], yArr[0:99]) # 8 * 1
        yHat = xArr[100:199] * ws
        print(rssError(yArr[100:199],yHat.T.A))

      

      从中可以看出使用训练数据集做测试集时,k=0.1时的误差最小,但使用不同训练集的数据做测试数据集时,k=0.1的误差最大,说明了可能出现了过拟合的情况,因此在选取k值时应选择使测试误差最小的值。同时我们可以看到,当k=1时,局部加权线性回归和简单的线性回归得到的效果差不多。这也表明一点,必须在未知数据上比较效果才能选取到最佳模型。

    参考:

    《机器学习实战第8章》

    http://cuijiahua.com/blog/2017/11/ml_11_regression_1.html

  • 相关阅读:
    Passion回来了
    VS.NET Addin在Design time获取控件值
    [过时的消息]VS2005 Shipped!
    为asp.net程序添加自定义配置区域
    Visual Studio .NET 2002 Service Pack 1 出来了
    Winform下通过控件名称来获取控件
    new blog, new life
    我的hotmail信箱容量变成2G了!
    first day in microsoft
    在client端通过java script调用Web Service
  • 原文地址:https://www.cnblogs.com/weiququ/p/9526515.html
Copyright © 2020-2023  润新知