Python机器学习日记(十一)

回归的目的是预测数值型的目标值。一句输入写出一个目标值得计算公式就是所谓的回归方程,求回归系数的过程就是回归。一旦有了这些回归系数,在给定输入,做预测就非常容易了。具体做法是用回归系数乘以输入值,再将结果全部加到一起,就得到了预测值。

怎样从一大堆数据里求出回归方程呢?嘉定输入数据存放在矩阵x中,而回归系数存放在向量w中,那么对于给定的数据x1,预测结果将会通过给出。现在有一些x和对应的Y,怎样才能找到w呢?一个常用的方法就是找出是误差最小的w。这里的误差是指预测y值和真实y值之间的差值,使用该误差的简单累加将使得正差值和负差值相互抵消,故采用平方误差:

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 = mat(xArr)
    yMat = mat(yArr).T
    #首先读取x,y并将他们保存在矩阵中
    xTx =xMat.T*xMat
    if linalg.det(xTx) == 0.0:
        print("This matrix is singular,cannot do inverse")
        return
    #计算矩阵行列式如果为0,则计算逆矩阵时将出现错误
    #linalg,det()可以直接调用用来计算行列式
    ws = xTx.I*(xMat.T*yMat)
    return ws
    #行列式非零返回w

"""
该函数用来计算最佳拟合直线
"""

xArr,yArr = loadDataSet('F:\python\machinelearninginaction\Ch08\ex0.txt')
print(xArr[0:2])
ws = standRegres(xArr, yArr)
print(ws)

 [[1.0, 0.067732], [1.0, 0.42781]]


[[3.00774324]
 [1.69532264]]

第一个值总是等于0,即X0,我们假定偏移量就是一个常数。第二个值X1,就是横坐标值

ws存放的就是回归系数。再用内积来预测y的时候,第一位将乘以前面的常数X0,第二维将乘以输入变量X1.。因为前面假定X0=1,所以最终会得到y=ws[0]+ws[1]*X1这里的y实际是预测树的,为了和真是的y值区分开,将其记为yHat。下面用新的ws的值计算yHat

xMat = mat(xArr)
yMat = mat(yArr)
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(xMat[:,1].flatten().A[0],yMat.T[:,0].flatten().A[0])
xCopy = xMat.copy()
xCopy.sort(0)
yHat = xCopy*ws
ax.plot(xCopy[:,1],yHat)
plt.show()

 

 通过计算预测值yHat序列和真实值y序列的匹配程度--计算这两个序列的相关系数就可以比较结果的好坏。可以通过corrcoef(yEstimate,yActual)来计算

yHat = xMat*ws
print(corrcoef(yHat.T,yMat))

[[1.         0.98647356]
 [0.98647356 1.        ]]

该矩阵包含所有两两组合的相关系数。对角线上的数据是1.0。因为yHat和自己的匹配是最完美的


局部加权线性回归(LWLR)

在处理线性回归时一定要尽量避免欠拟合现象,可以在估计中引入一些偏差,从而降低预测的均方误差。其中一个方法就是局部加权线性回归。我们给待预测点附近的每个点赋予一定的权重,然后在这个自己上基于最小均方误差来进行普通的回归。这种算法与kNN一样,每次预测剧需要实现选去除对用的数据子集,该算法解出的回归系数w的形式如下:

                                                          

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

LWLR使用“核”来对附近的点赋予更高的权重,最常用的就是高斯核。

                                           

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

def lwlr(testPoint,xArr,yArr,k=1.0):
    xMat = mat(xArr)
    yMat = mat(yArr).T
    m = shape(xMat)[0]
    weights = mat(eye((m)))
    # 读取数据并创建矩阵,之后对创建对角权重矩阵weights
    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)
    #算法遍历数据集,计算每个样本点的对应的权重值
    #随着样本点与待预测点的距离的递增,权重讲义指数级衰减
    #暑促参数k控制衰减的速度
    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
#为数据集中每个点调用lwlr(),有助于求解k的大小

"""
该段代码的作用是:
给定x空间中任意一点,计算出对应的预测值yHat。
"""

 

 k=0.003

 

 k=0.01

 可以看到k=0.01时得到了非常好的效果,而k=0.003纳入了太多的噪声点,拟合的直线与数据点过于贴近,所以是一个过拟合的例子。接下来将对过拟合和欠拟合进行量化分析。

理发跑步拿快递,拒绝三分钟热度


岭回归

如果特征比样本点还多(n>m),也就是说输入数据的矩阵X不是满秩矩阵,费满秩矩阵再求逆时会出现问题。为了解决这个问题,引入了岭回归。

简单来说,岭回归就是在矩阵

其中矩阵I是一个m*m的单位矩阵,对角线上元素全为1,其他元素全为0.进而λ是一个用户定义的数值。在这种情况下,回归系数的计算公式将会变成: 

                                         

这里通过引入λ来限制了所有w之和,通过引入该惩罚项,能减少不重要的参数,这个技术在统计学中也叫作缩减。

岭回归中使用了单位矩阵乘以向量λ,其中的单位矩阵I,值1贯穿整个对角线,其余元素全为0.也就是在0构成的平面上有一条1组成的“岭”

缩减法可以取掉不重要的参数,取得更好的预测效果。这里通过预测误差最小化得到λ,数据获取之后,首先抽取一部分数据用于测试,剩余的用作训练集来训练参数w。训练完毕后在测试集上预测性能。通过选取不同的λ来重复上述测试过程,最终的得到一个使预测误差最小的λ。

def ridgeRegres(xMat,yMat,lam=0.2):
    xTx = xMat.T*xMat
    #首先构建矩阵
    denom = xTx+eye(shape(xMat)[1])*lam
    #用lam乘以单位矩阵
    if linalg.det(denom) == 0.0:
        print("This matrix is singular,cannot do inverse")
        return
    #检查行列式是否为0
    ws = denom.I*(xMat.T*yMat)
    return ws

def ridgeTest(xArr,yArr):
    xMat = mat(xArr)
    yMat = mat(yArr).T
    yMean = mean(yMat,0)
    yMat = yMat-yMean
    xMeans = mean(xMat,0)
    xVar = var(xMat,0)
    xMat = (xMat-xMeans)/xVar
    #数据标准化的过程,具体做法是所有的特征值都减去各自的均值并除以方差
    numTestPts = 30
    wMat = zeros((numTestPts,shape(xMat)[1]))
    for i in range(numTestPts):
        ws = ridgeRegres(xMat, yMat,exp(i-10))
        wMat[i,:] = ws.T
    return wMat
#最后将所有的回归系数输出到一个矩阵并返回
"""
第一个函数用于计算回归系数,第二个函数用于在一组λ上测试结果
"""

abX,abY = loadDataSet('F:\python\machinelearninginaction\Ch08\ex0.txt')
ridgeWeights = ridgeTest(abX,abY)
#这样就得到了30个不同的lambda所对应的回归系数
#接下来看一下缩减的效果
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(ridgeWeights)
plt.show()

 

自己的代码没有出现数据曲线,在网上找了个对应曲线,未能找到为啥没出现曲线的原因。。。

根据图可以看出,在最左边,可以得到所有系数的原始值,而在右边,系数全部缩减成0。早中间部分的某值讲课以取得最好的预测效果。为了定量的找到最佳参数值还需要进行交叉验证。

下面将对lasso方法稍作介绍。


lasso

在增加如下约束时,普通的最小二乘法回归会得到与岭回归一样的公式:

                                                        

上式限定了所有回归系数的平方和不能大于λ。另一个缩减方法lasso也对回归系数作了限定,对应约束条件如下:

                                                          

唯一不同的地方在于,这个约束条件用绝对值取代了平方和。在λ足够小的时候,一些洗漱会因此被迫缩减到0,这个特性可以让我们更好的理解数据。下面介绍向前逐步回归

该算法可以得到lasso差不多的效果,属于一种贪心算法,及每一步都尽可能地减小误差。一开始把所有的权重都设为1,然后每一步所做的决策是对某个权重增加或者减少一个很小的值,伪代码如下:、

数据标准化,使其分布满足0均值和单位方差

在每轮迭代过程中:

  设置当前最小误差lowestError为正无穷

  对每个特征:

     增大或缩小:

          改变一个洗漱得到一个新的w

          计算新w下的误差

          如果误差Error小于当前最小误差lowestError:设置Wbest等于当前的w

    将W设置为新的Wbest

def stageWise(xArr,yArr,eps=0.01,numIt=100):
    xMat = mat(xArr)
    yMat = mat(yArr).T
    #首先将输入数据转换并存入矩阵中
    yMean = mean(yMat,0)
    #然后把特征值按照均值为0方差为1进行标准化处理
    yMat = yMat-yMean
    xMat = regularize(xMat)
    m,n = shape(xMat)
    returnMat = zeros((numIt,n))
    ws = zeros((n,1))
    #创建向量ws来保存w的值,并为了实现贪心算法建立了ws的两份副本
    wsTest = ws.copy()
    wsMax = ws.copy()
    for i in range(numIt):
        #接下来的优化过程需要迭代numIt次,并且在每次迭代时都打印出w向量,用于分析算法
        #执行的过程和效果
        print(ws.T)
        lowestError = 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
        #在所有特征值上运行两次for循环,分别计算增加或减少该特征值对误差的影响
        #这里使用的是通过rssError()得到的平方误差,该误差初始值设为正无穷
        #经过与所有的误差比较后取最小的误差。整个过程循环迭代进行
    return returnMat
"""
该算法是一个逐步线性回归算法的实现。该数据的输入包括:输入数据xArr和预测变量yArr
此外还有两个参数:一个是eps表示每次迭代需要调整的步长;另一个是numIt,表示迭代次数
"""

xArr,yArr = loadDataSet('F:\python\machinelearninginaction\Ch08\\abalone.txt')
print(stageWise(xArr, yArr,0.01,200))

 [[ 0.    0.    0.09  0.03  0.   -0.49  0.    0.36]]
[[ 0.    0.    0.09  0.03  0.   -0.5   0.    0.36]]
[[ 0.    0.    0.09  0.03  0.   -0.51  0.    0.36]]
[[ 0.    0.    0.09  0.03  0.   -0.51  0.    0.37]]
[[ 0.    0.    0.09  0.03  0.   -0.52  0.    0.37]]
[[ 0.    0.    0.09  0.03  0.01 -0.52  0.    0.37]]
[[ 0.01  0.    0.09  0.03  0.01 -0.52  0.    0.37]]
[[ 0.01  0.    0.09  0.03  0.01 -0.53  0.    0.37]]
[[ 0.01  0.    0.09  0.03  0.02 -0.53  0.    0.37]]

有几个wi都是0,这表明他们不对目标值造成任何影响,也就是说这些特征很可能是不需要的。另外,在参数eps设置为0.01的情况下,一段时间后系数就已经饱和并在特定值之间来回震荡,这是因为步长太大的缘故。下面试着用更小的步长和更多的步数。

print(stageWise(xArr, yArr,0.001,5000))

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值