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

标准回归函数和数据导入函数:

import numpy as np

#打开一个用tab键分割的文本文件
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 standRegres(xArr, yArr):
    xMat = np.mat(xArr); yMat = np.mat(yArr).T
    xTx = xMat.T*xMat #计算x^Tx
    #判断行列式是否为0
    if np.linalg.det(xTx) == 0.0:
        print("This matrix is singular, cannot do inverse") #计算逆矩阵出现错误
        return
    ws = xTx.I * (xMat.T*yMat) #I是逆矩阵
    return ws
    
def plotDataSet():
    xArr, yArr = loadDataSet('ex0.txt')                     #加载数据集
    n = len(xArr)                                           #数据个数
    xcord = []; ycord = []                                  #样本点
    for i in range(n):
        xcord.append(xArr[i][1]); ycord.append(yArr[i])     #样本点
    fig = plt.figure()
    ax = fig.add_subplot(111)                               #添加subplot
    ax.scatter(xcord, ycord, s = 20, c = 'blue',alpha = .5) #绘制样本点
    plt.title('DataSet')                                    #绘制title
    plt.xlabel('X')
    plt.ylabel('Y')
    plt.show()


if __name__ == '__main__':
    plotDataSet()

线性回归的一个问题是有可能出现欠拟合现象,因为它求的是具有最小均方误差的无偏估计。

局部加权线性回归:给待预测点附近的每个点赋予一定的权重,在这个子集上基于最小均方差来进行普通的回归,与kNN一样,这种算法每次预测均需要事先选取对应的数据子集,该算法解出回归系数w的形式如下: w = (XTWX) -1 XT Wy 其中w是一个矩阵,用来给每个数据点赋予权重

LWLR使用核来对附近的点赋予更高的权重

最常用的是高斯核,对应的权重w(i,j)=exp(|x(i)-x|/-2k2)

def lwlr(testPoint, xArr, yArr, k=1.0):
    xMat = np.mat(xArr);yMat = np.mat(yArr).T
    m = np.shape(xMat)[0]
    weights = np.mat(np.eye((m)))  #创建对角矩阵
    for j in range(m):
        diffMat = testPoint - 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:
        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 = np.shape(testArr)[0]
    yHat = np.zeros(m)
    for i in range(m):
        yHat[i] = lwlr(testArr[i],xArr,yArr,k)
    return yHat

如果数据的特征比样本点还多,也就是说输入数据的矩阵x不是满秩矩阵,非满秩矩阵在求逆在求逆时会出现问题。

岭回归:就是在矩阵xTX上加上一个λI从而使得矩阵非奇异,进而能对xTX+λ求逆

在这种情况下,回归系数的计算公式将变为:W = (xTX+λI)-1XTy
这里通过引入λ来限制了所有w之和,通过引入该惩罚项,能够减少不重要的参数,这个技术在统计学也叫做缩减。

#计算回归系数
def ridgeRegres(xMat, yMat, lam=0.2):
    xTx = xMat.T*xMat
    denom = xTx + np.eye(np.shape(xMat)[1])*lam
    #将lam设为0的时候仍可能出现错误,检查行列式是否为0
    if np.linalg.det(denom) == 0.0:
        print("This matrix is singular, cannot do inverse")
        return
    ws = denom.I * (xMat.T*yMat)
    return ws

#用于在一组λ上测试结果
def ridgeTest(xArr, yArr):
    xMat = np.mat(xArr); yMat = np.mat(yArr).T
    yMean = np.mean(yMat,0)
    yMat = yMat - yMean
    xMeans = np.mean(xMat,0)
    xVar = vars(xMat,0) #转换为字典
    xMat = (xMat - xMeans) / xVar
    numTestPts = 30
    wMat = np.zeros((numTestPts,np.shape(xMat)[1]))
    for i in range(numTestPts):
        ws = ridgeRegres(wMat, yMat, np.exp(i-10))
        wMat[i,:] = ws.T
    return wMat

lasso:对回归系数做了限定
与岭回归的唯一不同点在于,这个约束条件使用绝对值取代了平方和

前向逐步回归:

伪代码如下:
数据标准化,使其分布满足0均值分布和单位方差
在每轮迭代过程中:
    设置当前最小误差lowestError为正无穷
    对每个特征:
         增大或缩小:
              改变一个系数得到一个新的w
              计算新w下的误差
              如果误差Error小于当前最小误差lowestError,设置Wbest等于当前的w
         将W设置为新的Wbest


```python
#逐步线性回归算法
#输入数据xArr,预测变量yArr,eps表示每次迭代需要调整的步长,另一个numIt,表示迭代次数
def stageWise(xArr,yArr,eps=0.01,numIt=100): 
    #标准化处理
    xMat = np.mat(xArr); yMat = np.mat(yArr).T
    yMean = np.mean(yMat,0)
    yMat = yMat - yMean
    xMat = np.regularize(xMat)
    m,n = np.shape(xMat)
    returnMat = np.zeros((numIt,n))
    ws = np.zeros((n,1));wsTest = ws.copy();wsMax = ws.copy() #为了实现贪心算法建立两个ws的两份副本
    for i in range(numIt):
        #每次迭代都打印w向量
        print(ws.T)
        loweastError = np.inf
        for j in range(n):
            for sign in [-1,1]:
                wsTest = ws.copy() 
                wsTest[j] += np.epa*sign
                yTest = xMat*wsTest
                #平方误差
                rssE = np.rssError(yMat.A,yTest.A)
                if rssE < loweastError:
                    loweastError = rssE
                    wsMax = wsTest
        ws = wsMax.copy()
        returnMat[i,:] = ws.T
    return  returnMat

如何用缩减法确定最佳回归系数:

def crossValitation(xArr, yArr, numVal=10):
    m = len(yArr)
    indexList = range(m) #计算数据点m的个数
    errorMat = np.zeros(numVal,30)
    for i in range(m):
        #创建训练集和测试机容器
        trainX = [];trainY = []
        testX = []; testY = []
        np.random.shuffle(indexList) #将其中的元素进行混洗
        for j in range(m):
            if j < m*0.9: #将90%的数据集加入训练集 剩下的加入测试集
                trainX.append(xArr(indexList[j]))
                trainY.append(yArr(indexList[j]))
            else:
                testX.append(xArr[indexList[j]])
                testY.append(yArr[indexList[j]])
    #数据混洗完就建立一个wMat矩阵来保存岭回归中的所有回归系数
    wMat = ridgeTest(trainX,trainY)
    for k in range(30):
        matTestX = np.mat(testX);matTrainX =np.mat(trainX)
        meanTrain = np.mean(matTrainX,0)
        varTrain = vars(matTrainX,0)
        matTrainX = (matTestX - matTrainX)/varTrain
        yEst = matTestX * np.mat(wMat[k,:].T + np.mean(trainY))
        errorMat[i:k]==rssError(yEst.T.A,np.array(testY)) #计算误差,保存了每个λ对应的多个误差值
    meanError = np.mean(errorMat,0) #计算误差的均值
    minMean = float(min(meanError))
    bestWeights = wMat(np.nonzero(meanError==minMean))
    xMat = np.mat(xArr);yMat = np.mat(yArr).T
    meanX = np.mean(xMat,0);varX = vars(xMat,0)
    #对数据进行还原
    unReg = bestWeights/varX
    print("the best model from Ridge Regression is:\n",unReg)
    print("with constant term:",-1*sum(np.multiply(meanX,unReg)) + np.mean(yMat))

你可能感兴趣的:(机器学习实战,python,机器学习)