回归预测数值型数据

一.线性回归

回归的目的是预测数值型的目标值。最直接的办法是依据输入写成一个目标值的计算公式。

 

回归方程:y=a_1*x_1+a_2*x_2

 

其中的 a1 和 a2 称作回归系数,求这些回归系数的过程就是回归。一旦有了这些回归系数,再给定输入,做预测就非常容易了,具体的做法是用回归系数乘以输入值,再将结果全部加在一起,就得到了预测值

 应当怎样从一大堆数据里求出回归方程呢?假定输入数据存放在矩阵 X 中,而回归系数存放在向量 W 中,那么对于给定的数据 x1,预测结果将会通过

给出。现在的问题是,有一些 x 个对应的 Y,怎样才能找到 w 呢?一个常用的方法就是找出误差最小的 w。这里的误差是指预测 y 值和真实 y 值之间的差值,使用该差值的简单累加将使得正差值和发差值相互抵消,所以使用平方误差公式:

 用矩阵表示为:

 如果对 w 求导,得到:

令其等于零,解出 w 如下:

w 上方的小标记表示,这是当前可以估计出的 w 的最优解。

值得注意的是,上述公式中包含也就是需要对矩阵求逆,因此这个方程只在逆矩阵存在的时候适用(代码中可以用伪逆矩阵)。上述的最佳 w 求解的统计学中的常见问题,除了矩阵方法外还有其他方法可以解决。该方法也称为 OLS,即普通最小二乘法(ordinary least squares)。

 

利用一个普通数据集画出散点图及最佳拟合直线如下:

from numpy import *
import numpy as np
import operator
from os import listdir
import matplotlib.pyplot as plt

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  
  
#计算最佳拟合曲线  
def standRegress(xArr,yArr):  
    xMat = mat(xArr); yMat = mat(yArr).T  #.T代表转置矩阵  
    xTx = xMat.T * xMat  
    if linalg.det(xTx) ==0.0: #linalg.det(xTx) 计算行列式的值  
        print ("This matrix is singular , cannot do inverse")  
        return  
    ws = xTx.I * (xMat.T * yMat)  
    return ws  
  
#测试上边的函数  
xArr,yArr = loadDataSet("ex0.txt")  
ws = standRegress(xArr, yArr)  
print ("ws(相关系数):",ws)    #ws 存放的就是回归系数  
  
#画图展示  
def show():  
    import matplotlib.pyplot as plt  
    xMat = mat(xArr); yMat = mat(yArr)  
    yHat = xMat*ws  
    fig = plt.figure() #创建绘图对象  
    ax = fig.add_subplot(111)  #111表示将画布划分为1行2列选择使用从上到下第一块  
    #scatter绘制散点图  
    ax.scatter(xMat[:,1].flatten().A[0],yMat.T[:,0].flatten().A[0])  
    #复制,排序  
    xCopy =xMat.copy()  
    xCopy.sort(0)  
    yHat = xCopy * ws  
    #plot画线  
    ax.plot(xCopy[:,1],yHat)  
    plt.show()  
    
   
yHat = mat(xArr) * ws  #yHat = xMat * ws  
print ("相关性:",corrcoef(yHat.T,mat(yArr))) 

show()

 

二.局部加权线性回归

 

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

 

其中一个方法是局部加权线性回归(Locally Weighted Linear Regression,LWLR)。在该算法中,我们给待预测点附近的每个点赋予一定的权重;然后与8.1节类似,在这个子集上基于最小均方差来进行普通的回归。与 kNN 一样,这种算法每次均需要事先取出对应的数据子集。该算法解出回归系数 w 的形式如下:

其中 w 是一个矩阵,用来给每个数据点赋予权重。

LWLR 使用“核”来对附近的点赋予更高的权重。核的类型可以自由选择,最常用的核就是高斯核,其对应的权重如下:

 这样就构建了一个只含对角元素的权重矩阵 w,并且点 x 与 x(i) 越近,w(i,i) 将会越大。上述公式包含一个需要用户指定的参数 k,它决定了对附近的点赋予多大的权重,这也就是使用 LWLR 时唯一需要考虑的参数

 

下图给出了k在三种不同取值下的结果图:

k = 1.0 时的模型效果与最小二乘法差不多,k=0.01时该模型可以挖出数据的潜在规律,而 k=0.003时则考虑了太多的噪声,进而导致了过拟合现象。

def lwlr(testPoint,xArr,yArr,k=1.0):  
    xMat = mat(xArr); yMat = mat(yArr).T  
    m = shape(xMat)[0]  
    weights = mat(eye((m)))   #产生对角线矩阵  
    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  
  
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  
  
  
xArr,yArr = loadDataSet('ex0.txt')  
print ("k=1.0:",lwlr(xArr[0],xArr,yArr,1.0))  
print ("k=0.01:",lwlr(xArr[0],xArr,yArr,0.01))  
print ("k=0.003:",lwlr(xArr[0],xArr,yArr,0.003)) 

#画图  
def showlwlr():  
    yHat = lwlrTest(xArr, xArr, yArr, 0.01)  
    xMat = mat(xArr)  
    srtInd = xMat[:,1].argsort(0)  
    xSort = xMat[srtInd][:,0,:]  
  
    import matplotlib.pyplot as plt  
    fig = plt.figure() #创建绘图对象  
    ax = fig.add_subplot(111)  #111表示将画布划分为1行2列选择使用从上到下第一块  
    ax.plot(xSort[:,1],yHat[srtInd])  
    #scatter绘制散点图  
    ax.scatter(xMat[:,1].flatten().A[0],mat(yArr).T[:,0].flatten().A[0],s=2,c='red')  
    plt.show()

show()

三.使用回归算法预测鲍鱼的年龄

“abalone.txt”数据集部分如下:

 

用函数ressError()计算出预测误差,可以看出使用较小的核将得到较低的误差,但核过小也会造成过度拟合。

abX, abY = loadDataSet('abalone.txt')
yHat01 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 0.1)
yHat1 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 1)
yHat10 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 10)
print(rssError(abY[0:99], yHat01.T)) # 56.7886874305
print(rssError(abY[0:99], yHat1.T)) # 429.89056187
print(rssError(abY[0:99], yHat10.T)) # 549.118170883

ws = standRegres(abX[0:99], abY[0:99])
yHat = np.mat(abX[100:199]) * ws
print(rssError(abY[100:199], yHat.T.A)) # 518.636315325

下图分别是核为0.1、1、10及简单线性回归时的误差,可以看出简单线性回归达到了与局部加权线性回归类似的效果,也表明在未知数据上比较才能选取到最佳模型。

 

此篇展示了如何使用局部加权线性回归来构建模型,可以得到比普通线性回归更好的效果。局部加权线性回归的问题在于,每次必须在整个数据集上运行。也就是说为了做出预测,必须保存所有的训练数据。

猜你喜欢

转载自www.cnblogs.com/yue-guan/p/1072regression.html
今日推荐