1 用线性回归找到最佳拟合直线

线性回归

优点:结果易于理解,计算上不复杂
缺点:对非线性的数据拟合不好
使用数据类型:数值型数据和标称型数据。

  • 回归方程:是根据样本资料通过回归分析所得到的反映一个变量(因变量)对另一个或一组变量(自变量)的回归关系的数学表达式
  • 回归系数:在回归方程中表示自变量x对因变量y影响大小的参数
  • 回归:求回归系数的过程
    • 说到回归,一般都是指线性回归(linear regression),还存在非线性回归模型
    • 假定输入数据存放在矩阵XXX中,而回归系数存放在向量ω\omegaω中,那么对于给定的数据X1X_1X1​,预测结果将会通过:Y1=X1TωY_1 = X_1^T\omegaY1​=X1T​ω
    • 现在的问题是,手里有一些x和对应的y,如何找到ω\omegaω呢?
    • 常用的方法是找到使误差(一般采用平方误差,否则正负误差会相互抵消)最小的w 。平方误差可写作:
      ∑i=1m(yi−xiTω)2\sum_{i=1}^m(y_i - x_i^T\omega)^2 i=1∑m​(yi​−xiT​ω)2
    • 用矩阵表示还可以写成:(Y−Xω)T(Y−Xω)(Y - X\omega)^T(Y - X\omega)(Y−Xω)T(Y−Xω)
    • 对ω\omegaω求导: 令其为0,得到最优解、最佳估计:
      ω^=(XTX)−1XTy\widehat{\omega} = (X^TX)^{-1}X^Ty ω=(XTX)−1XTy
    • 公式中的(XTX)−1(X^TX)^{-1}(XTX)−1是对矩阵求逆,需要在代码中判断逆矩阵是否存在,可以调用NumPy中函数linalg.det()来计算行列式,如果行列式为零(奇异矩阵),那么计算逆矩阵的时候会出现错误.
    • 这种求解最佳ω\omegaω的方法称为OLS“普通最小二乘法”

python代码实现:

import numpy as np
def loadDataSet(fileName):"""加载数据集:param fileName: 文件名:return:dataMat:数据矩阵labelMat:标签矩阵"""numFeat = len(open(fileName).readline().split('\t')) - 1dataMat = []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, labelMatdef standRegres(xArr, yArr):"""线性回归:param xArr: 输入的样本数据,包含每个样本数据的feature:param yArr: 对应于输入数据的类别标签,也就是每个样本对应的目标变量:return:ws:回归系数"""# np.mat()函数将xArr,yArr转换为矩阵,mat().T代表的是对矩阵进行转置操作xMat = np.mat(xArr)yMat = np.mat(yArr).T# 矩阵乘法的条件是左矩阵的列数等于右矩阵的行数xTx = xMat.T * xMat# 因为要用到xTx逆矩阵,所以事先需要确定计算得到的xTx是否可逆,条件是矩阵的行列式不为0# np.linalg.det()函数是用来求得矩阵的行列式的,如果矩阵的行列式为0,则这个矩阵是不可逆的,就无法进行接下来的运算if np.linalg.det(xTx) == 0.0:print("this matrix is singular,cannot do inverse")return# 最小二乘法ws = xTx.I * (xMat.T * yMat)return ws

2 局部加权线性回归

  • 线性回归会出现欠拟合现象→\rightarrow→它求的是最小均方误差的无偏估计。

    • 可以在估计中引入一些偏差bias,从而降低预测的均方误差
    • 其中一个方法是局部加权线性回归,该算法中给待测点附近的每个点赋予一定的权重,然后在这个子集上基于最小均方差来进行普通的回归。与kNN一样,此算法每次预测均需事先选取出对应的数据子集
    • 该算法解出的回归系数的形式如下:
      ω^=(XTWX)−1XTWy\widehat{\omega} = (X^TWX)^{-1}X^TWy ω=(XTWX)−1XTWy
    • 其中W是一个矩阵,用来给每个数据点赋予权重
  • 局部加权线性回归使用“核”(与支持向量机中的核类似)来对附近的点赋予更高的权重
  • 核的类型可以自由选择,最常用的是高斯核,高斯核对应的权重如下:
    ω(i,i)=exp(∣x(i)−x∣2−2k2)\omega(i,i) = exp(\frac {|x^{(i)} - x|_2}{-2k^2}) ω(i,i)=exp(−2k2∣x(i)−x∣2​​)

    • 这样就构建了一个只含对角元素的权重矩阵W,并且点x(预测点)与x(i)x^{(i)}x(i)越近(样本点),ω(i,i)\omega(i,i)ω(i,i)将会越大
    • 公式中的k需要用户指定,它决定了对附近的点赋予多大的权重
    • 注意区分权重W和回归系数ω\omegaω,与kNN一样,该加权模型认为样本点距离越近,越可能符合同一个线性模型

x为某个预测点,x(i)x^{(i)}x(i)为样本点,样本点距离预测点越近,贡献的误差越大(权值越大),越远则贡献的误差越小(权值越小)。
python代码实现:

def lwlr(testPoint, xArr, yArr, k=1.0):"""局部加权线性回归,在待预测点附近的每一个点赋予一定的权重,在子集上基于最小均方差来进行普通的回归:param testPoint:样本点:param xArr:样本的特征数据,即feature:param yArr:每个样本对应的类别标签,即目标变量:param k:关于赋予权重矩阵的核的每一个参数,与权重的衰减速率有关:return:testPoint*ws:数据点与具有权重的系数相乘得到的预测点"""xMat = np.mat(xArr)yMat = np.mat(yArr).Trow = np.shape(xMat)[0]# eye()返回一个对角线元素为1,其他元素为0的二维数组,创建传递矩阵weightsweights = np.mat(np.eye(row))for j in range(row):# testPoint的形式是一个行向量# 计算testPoint与输入样本点之间的距离,然后下面计算出每个样本贡献误差的权值diffMat = testPoint - xMat[j, :]# k控制衰减的速度weights[j, j] = np.exp(diffMat * diffMat.T / (-2.0 * k ** 2))# 根据矩阵乘法计算xTx,其中的weights矩阵是样本点对应的权值矩阵xTx = xMat.T * (weights * xMat)if np.linalg.det(xTx) == 0.0:print("this matrix is singular,cannot do inverse")returnws = xTx.I * (xMat.T * (weights * yMat))return testPoint * wsdef lwlrTest(testArr, xArr, yArr, k=1.0):"""测试局部加权线性回归函数:param testArr:测试样本点:param xArr:样本的特征数据,即feature:param yArr:每个样本对应的类别标签,即目标变量:param k:关于赋予权重矩阵的核的每一个参数,与权重的衰减速率有关:return:"""row = np.shape(testArr)[0]yHat = np.zeros(row)for i in range(row):yHat[i] = lwlr(testArr[i], xArr, yArr, k)return yHat

3 实例:预测鲍鱼的年龄

def rssError(yArr, yHatArr):return ((yArr - yHatArr) ** 2).sum()
if __name__ == "__main__":abX, abY = loadDataSet('abalone.txt')print("训练集与测试集相同:局部加权线性回归")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('k=0.1时,误差大小为:', rssError(abY[0:99], yHat01.T))print('k=1时,误差大小为:', rssError(abY[0:99], yHat1.T))print('k=10时,误差大小为:', rssError(abY[0:99], yHat10.T))print('')print("训练集与测试集不同:局部加权线性回归")yHat01 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 0.1)yHat1 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 1)yHat10 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 10)print('k=0.1时,误差大小为:', rssError(abY[100:199], yHat01.T))print('k=1时,误差大小为:', rssError(abY[100:199], yHat1.T))print('k=10时,误差大小为:', rssError(abY[100:199], yHat10.T))print('')print("训练集与测试集不同:简单的线性回归与k=1时的局部加权线性回归对比:")print('k=1时,误差大小为:', rssError(abY[100:199], yHat1.T))ws = standRegres(abX[0:99], abY[0:99])yHat = np.mat(abX[100:199]) * wsprint('简单的线性回归误差大小:', rssError(abY[100:199], yHat.T.A))plt.show()

4 缩减系数来“理解”数据

  • 如果数据的特征比样本点还多(n>m)应该怎么办?是否还可以使用线性回归和之前的方法来做预测?

    • 答案是否定的,即不能再使用前面介绍的方法。这是因为在计算矩阵求逆的时候会出错(如果特征比样本点还多(n > m),也就是说输入数据的矩阵x 不是满秩矩阵。非满秩矩阵求逆时会出现问题。)
  • 为了解决这个问题,引入了缩减方法:岭回归,lasso法和前向逐步回归(正则化,通过在模型中增加额外信息来解决过拟合、引入惩罚项,降低模型参数的影响)。

4.1 岭回归

  • 岭回归(正则化线性归回方法)就是在矩阵上加一个λI从而使得矩阵非奇异,进而能求逆。其中矩阵I是一个单位矩阵, 对角线上元素全为1,其他元素全为0。而(“岭”)λ是一个用户定义的数值。
  • 在这种情况下,回归系数的计算公式将变成:ω^=(XTX+λI)−1XTy\widehat{\omega} = (X^TX + \lambda I)^{-1}X^Tyω=(XTX+λI)−1XTy
  • 岭回归最先用来处理特征数多于样本数的情况,现在也用于在估计中加入偏差,从而得到更好的估计。这里通过引入λ 来限制了所有w 之和,通过引入该惩罚项,能够减少不重要的参数,这个技术在统计学中也叫作缩减。

python代码实现

def ridgeRegres(xMat, yMat, lam=0.2):""":param xMat::param yMat::param lam::return:"""xTx = xMat.T * xMatdenom = xTx + np.eye(np.shape(xMat)[1]) * lamif np.linalg.det(denom) == 0.0:print("this matrix is singular,cannot do inverse")ws = np.linalg.pinv(denom) * (xMat.T * yMat)ws = denom.I * (xMat.T * yMat)return wsdef ridgeTest(xArr, yArr):""":param xArr::param yArr::return:"""xMat = np.mat(xArr)yMat = np.mat(yArr).TyMean = np.mean(yMat, 0)yMat = yMat - yMeanxMeans = np.mean(xMat, 0)xVar = np.var(xMat, 0)xMat = (xMat - xMeans) / xVarnumTestPts = 30wMat = np.zeros((numTestPts, np.shape(xMat)[1]))for i in range(numTestPts):ws = ridgeRegres(xMat, yMat, np.exp(i - 10))wMat[i, :] = ws.Treturn wMat
if __name__ == "__main__":abX, abY = loadDataSet('abalone.txt')ridgeWeights = ridgeTest(abX,abY)fig = plt.figure()ax = fig.add_subplot(111)ax.plot(ridgeWeights)plt.show()


回归系数与log(λ)的关系,最左边λ最小时,8个系数的原始值与线性回归一样,最右边8个回归系数全部缩减为0,为找到最佳参数λ,还需要将ws乘以测试集比较原始测试集对比误差大小。0对应λ=exp(0−10)\lambda = exp(0-10)λ=exp(0−10),30对应λ=exp(30−10)\lambda=exp(30-10)λ=exp(30−10)

4.2 lasso

  • 在增加约束:所有回归系数的平方和不能大于λ的条件下、普通的最小二乘法回归会得到与岭回归一样的公式
    ∑k=1nωk2⩽λ\sum_{k=1}^n\omega_k^2\leqslant\lambda k=1∑n​ωk2​⩽λ

    • 限定了所有回归系数的平方和不能大于λ(L2正则化)。使用普通的最小二乘法回归在当两个或更多的特征相关时,可能会得到一个很大的正系数和一个很大的负系数。因为上述限制条件的存在,使用岭回归可以避免这个问题
  • 与岭回归类似,另一个缩减方法lasso也对回归系数做了限定,对应的约束条件如下:
    ∑k=1n∣ωk∣⩽λ\sum_{k=1}^n|\omega_k|\leqslant\lambda k=1∑n​∣ωk​∣⩽λ

    • 唯一的不同点在于,这个约束条件使用绝对值取代了平方和(L1正则化)。在λ 足够小的时候,一些系数会因此被迫缩减到0.这个特性可以帮助我们更好地理解数据。
    • 计算复杂度高(二次规划算法求解)

4.3 前向逐步回归

  • 前向逐步回归算法可以得到与lasso 差不多的效果,但更加简单。它属于一种贪心算法

    • 即每一步都尽可能减少误差。一开始,所有权重都设置为1,然后每一步所做的决策是对某个权重增加或减少一个很小的值。

逐步线性回归算法的主要优点在于它可以帮助人们理解现有的模型并作出改进。当构建了一个模型后,可以运行该算法找出重要的特征,这样就有可能及时停止对那些不重要特征的收集。

4.5 权衡偏差与方差

  • 当应用缩减方法(如逐步线性回归或岭回归)时,模型也就增加了偏差(bias),与此同时减小了模型的方差(variance)

  • 模型和测量值之间存在的差异,叫做误差error。当考虑模型中存在“噪声”或者说误差时,必须考虑其来源。

    • 对复杂的过程简化,会导致模型和测量值之间出现“噪声”和误差
    • 无法理解数据的真实生成过程,也会导致差异的发生。
    • 测量过程本身也可能产生“噪声”或问题
    • 局部加权线性回归通过引入越来越小的核来不断增大模型的方差
    • 缩减法可以将一些系数缩减成很小的值或直接缩减为0,增大模型偏差。
    • 方差是模型之间的差异,而偏差指的是模型预测值与数据之间的差异。偏差与方差折中的概念在机器学习中十分流行
  • 方差度量了同样大小的训练集的变动所导致的学习性能的变化, 即 刻画了数据扰动所造成的影响

  • 偏差度量了学习算法的期望预测与真实结果的偏离程度,即 刻画了学习算法本身的拟合能力

  • 噪声表达了在当前任务上任何学习算法所能达到的期望泛化误差的下界, 即 刻画了学习问题本身的难度

4.6 实例:预测乐高玩具套装的价格

from time import sleep
import json
import urllib
def searchForSet(retX,retY,setNum,yr,numPce,origPrc):sleep(10)myAPIstr = 'get from code.google.com'searchURL = 'https://www.googleapis.com/shopping/search/v1/public/products?key=%s&country=US&q=lego+%d&alt=json' % (myAPIstr, setNum)pg = urllib.request.urlopen(searchURL)retDict = json.loads(pg.read())for i in range(len(retDict['items'])):try:currItem = retDict['items'][i]if currItem['product']['condition'] == 'new':newFlag = 1else: newFlag = 0listOfInv = currItem['product']['inventories']for item in listOfInv:sellingPrice = item['price']if  sellingPrice > origPrc * 0.5:print ("%d\t%d\t%d\t%f\t%f" % (yr,numPce,newFlag,origPrc, sellingPrice))retX.append([yr, numPce, newFlag, origPrc])retY.append(sellingPrice)except: print ('problem with item %d' % i)def setDataCollect(retX, retY):searchForSet(retX, retY, 8288, 2006, 800, 49.99)searchForSet(retX, retY, 10030, 2002, 3096, 269.99)searchForSet(retX, retY, 10179, 2007, 5195, 499.99)searchForSet(retX, retY, 10181, 2007, 3428, 199.99)searchForSet(retX, retY, 10189, 2008, 5922, 299.99)searchForSet(retX, retY, 10196, 2009, 3263, 249.99)def crossValidation(xArr,yArr,numVal=10):m = len(yArr)                           indexList = list(range(m))#创建numVal*30的误差矩阵##30的由来:ridgeTest()使用了30个不同的lambda值来创建不同的回归系数,即numTestPts = 30errorMat = np.zeros((numVal,30))for i in range(numVal):#创建测试集和训练集容器trainX=[]; trainY=[]testX = []; testY = []#打乱索引顺序,实现随机选取训练集和测试集数据点np.random.shuffle(indexList)#90%训练+10%测试for j in range(m):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组ws向量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)errorMat[i,k]=np.rssError(yEst.T.A,np.array(testY))#print errorMat[i,k]#计算不同岭回归ws下errorMat的平均值,观察平均性能  #meanErrors:1*30矩阵meanErrors = np.mean(errorMat,0)minMean = float(min(meanErrors))#nonzero(meanErrors==minMean)返回的是误差最小的索引,因此bestWeights为误差最小的那个w向量bestWeights = wMat[np.nonzero(meanErrors==minMean)]#岭回归使用了数据标准化,而standRegres没有,为了比较可视化,因此需要将数据还原#标准化后 Xreg = (x-meanX)/var(x),预测y=Xreg*w+meanY#因此,利用未标准化的x来计算y= x*w/var(x) - meanX*w/var(x) +meanY#其中unReg=w/varxMat = np.mat(xArr); yMat=np.mat(yArr).TmeanX = np.mean(xMat,0); varX = np.var(xMat,0)unReg = bestWeights/varX#print ("the best model from Ridge Regression is:\n",unReg)#特别注意这里的sum函数,一定是np.sum,因为一般的sum只能对list求和,而这里的参数是matrix#print ("with constant term: ",-1*np.sum(multiply(meanX,unReg)) + mean(yMat))yHat=xMat*unReg.T-1*np.sum(np.multiply(meanX,unReg)) + np.mean(yMat)return yHat

5 总结

  • “普通最小二乘法”:对于二维数据而言,线性回归就是找出一个一次函数去拟合数据,使得平方误差最小。是的,这里的损失函数是平方损失。
  • 并不是所有数据都能用线性回归来拟合,有的时候数据有转折或是其他规律。于是有了局部加权线性回归,该方法更加关注将要预测的数据周围的点,也就是通过高斯核给预测点周围的数据赋予权值,选择合适的高斯系数能使结果更好,当然这种算法的缺点是:对于每一个要预测的点,都要重新依据整个数据集计算一个线性回归模型出来,使得算法代价极高。
  • 岭回归是一种常见的shrinkage coefficient(缩减系数)方法,还有其他缩减方法,如lasso(效果很好但计算复杂)等。所谓shrinkage,就是通过一些手段来减少不重要的参数。岭回归是一种专用于线性数据分析的有偏估计回归方法,实质上是一种改良的最小二乘估计法,通过放弃最小二乘法的无偏性,以损失部分信息、降低精度为代价获得回归系数更为符合实际、更可靠的回归方法,对病态数据的拟合要强于普通最小二乘法

机器学习——regression相关推荐

  1. 李宏毅机器学习 Regression

    文章目录 1. Regression 2. Example Application 3. Step 3.1 Step1:模型 3.2 Step2:函数的评估标准 3.3 Step3:最优函数 4. 梯 ...

  2. 基于Pytorch的机器学习Regression问题实例(附源码)

    文章目录 一.写在前面 二.构建神经元网络 要解决什么问题 构建Python代码 运行结果 三.优化神经元网络 增加学习次数 调整LearningRate 调整优化方式 激活函数 小结 四.增加神经元 ...

  3. 普元部署包部署找不到构建_让我们在5分钟内构建和部署AutoML解决方案

    普元部署包部署找不到构建 Practical machine learning used to be hard - and still is in some specialized areas. Av ...

  4. PyCaret 2.0在这里-新增功能?

    There's no doubt that PyCaret is my favorite machine learning library. It's more developer-friendly ...

  5. R语言caret包构建机器学习回归模型(regression model)、使用DALEX包进行模型解释分析、特征重要度、偏依赖分析等

    R语言caret包构建机器学习回归模型(regression model).使用DALEX包进行模型解释分析.特征重要度.偏依赖分析等 目录

  6. python中的linearregression_【python+机器学习(2)】python实现Linear Regression

    欢迎关注哈希大数据微信公众号[哈希大数据] python实现多元线性回归算法(lr) 想必大家在很早之前就接触过函数的概念,即寻找自变量和因变量之间的对应关系,一元一次.多元一次.一元二次等等,表示的 ...

  7. 【机器学习】逻辑回归(Logistic Regression)

    注:最近开始学习<人工智能>选修课,老师提纲挈领的介绍了一番,听完课只了解了个大概,剩下的细节只能自己继续摸索. 从本质上讲:机器学习就是一个模型对外界的刺激(训练样本)做出反应,趋利避害 ...

  8. [机器学习] Coursera ML笔记 - 逻辑回归(Logistic Regression)

    引言 机器学习栏目记录我在学习Machine Learning过程的一些心得笔记,涵盖线性回归.逻辑回归.Softmax回归.神经网络和SVM等等.主要学习资料来自Standford Andrew N ...

  9. 机器学习之线性回归(Linear Regression)

    线性学习中最基础的回归之一,本文从线性回归的数学假设,公式推导,模型算法以及实际代码运行几方面对这一回归进行全面的剖析~ 一:线性回归的数学假设 1.假设输入的X和Y是线性关系,预测的y与X通过线性方 ...

最新文章

  1. 技术天地 | CSS-in-JS:一个充满争议的技术方案
  2. 解释Python的‘__enter __‘和‘__exit__‘
  3. 由system.currentTimeMillis() 获得当前的时间
  4. ElementUI中的el-table怎样实现每一列显示的是控件并能动态实现双向数据绑定
  5. 用python做数据分析pdf_利用python进行数据分析pdf
  6. Can't create directory 'E:\Repositories\***\db\transactions\138-41.txn':
  7. [原]Threads vs Processes in Linux 分析
  8. STM32 - 高级定时器的设定 - 基础-05 - 输出波形控制 -Complementary outputs and dead-time insertion 相位调整@互补输出和死区控制
  9. python socket多线程并发_【Python之旅】第五篇(三):Python Socket多线程并发
  10. SpringBoot2.0应用(五):SpringBoot2.0整合MyBatis
  11. 请简述一下RS485通讯连接方式及其应用?
  12. 用python算24点及原理详解
  13. 修改了Excel默认打开方式后仍然使用WPS打开的解决办法
  14. 夏敏捷 第39本著作《微信小程序游戏开发快速入门到实战》
  15. 如何显示计算机窗口的状态栏,如何让电脑任务栏不显示打开的程序或窗口方法...
  16. 怎样快速用计算机做字处理,怎样快速处理Word表格的技巧 -电脑资料
  17. 【计算机网路-第四章】IP地址和子网掩码
  18. OA系统八:用户登录一:基于LayUI框架开发登录页;
  19. javaeye上对李刚的书的差评
  20. 装箱问题c语言函数,C语言基于贪心算法解决装箱问题的方法

热门文章

  1. 渗透工程师日常探测漏洞全流程 初学者必看
  2. Android开发循序渐进实例5--网络访问例子
  3. k8s(一):基础核心概念
  4. 一些简单的shell实例
  5. 整理学习:100多道前端面试题(一起加油,且行且珍惜)
  6. Linux应用程序开发之man手册汉化+开发的简易流程说明
  7. 我是如何拿到腾讯头条美团小米的offer从小厂跳到大厂的?终局之战
  8. 几种常用可视化图表,该怎么用?
  9. java基础之接口_繁星漫天_新浪博客
  10. 1.单例模式_繁星漫天_新浪博客