线性回归的基本知识

线性回归能做什么

分类的目标变量是标量,线性回归的目的是预测数值型的目标值,要掌握以下技术:

  • 局部平滑技术
  • 更好的拟合数据
  • 回归在欠拟合状态下的缩减(shrinkage)
  • 偏差和方差的概念

线性回归找最佳拟合直线

先明白几个概念

  • regression equation:形如y = w1x1 + w2x2
  • regression weights:w1和w2
  • 什么叫回归:求w1和w2的过程
  • 如何做预测:求出regression weights之后,用回归系数乘以输入值,将结果加在一起,就得到预测值。

回归的一般方法

  • 收集数据:采用任意方法收集数据。
  • 准备数据:回归需要数值型数据,标称型数据将被转成二值型数据。
  • 分析数据:绘出数据的可视化二维图将有助于对数据做出理解和分析,在采用缩减法求得新回归系数之后,可以将新拟合线绘在图上作为对比。
  • 训练算法:找到回归系数。
  • 测试算法:使用R2或者预测值和数据的拟合度,来分析模型的效果。
  • 使用算法:使用回归,可以在给定输入的时候预测出一个数值,这是对分类方法的提升,因为这样可以预测连续型数据而不仅仅是离散的类别标签。

核心问题在于如何找出回归系数w?一个常用的方法是,找出使误差最小的w,误差是指预测y值和真实y值之间的差距。我们不能将所有的差距相加,因为这些差距有正有负,而应该统一平方后再累加。
平方误差为:\Sigma(yi-xiT*w)^2

计算w最优解的公式

regression.py

from numpy import *

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
    xTx = xMat.T * xMat
    if linalg.det(xTx) == 0.0:
        print("this matrix is singular,can not do inverse")
        return
    ws = xTx.I * (xMat.T*yMat)
    return ws

main.py

import regression
from numpy import *
import matplotlib.pyplot as plt

xArr,yArr = regression.loadDataSet('ex0.txt')   #xArr二维列表,yArr是一维列表
ws = regression.standRegress(xArr, yArr)     #求回归系数ws
xMat = mat(xArr)    #转换为矩阵
yMat = mat(yArr)
yHat = xMat*ws  #求出预测值

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()

新建一个regression.py文件,导入numpy模块,在文件中定义两个函数,一个用于导入数据集,参数为文件名,另一个standRegress用来计算最佳拟合直线。
Python split()方法 | 菜鸟教程 (runoob.com)
Python strip()方法 | 菜鸟教程 (runoob.com)
python中mat()函数
Python numpy linalg.det用法及代码示例
Matplotlib Pyplot | 菜鸟教程 (runoob.com)
python - 在Matplotlib中,参数在fig.add_subplot(111)中意味着什么? - ITranslater
Python中scatter函数参数详解
Python中scatter函数参数详解
[python中flatten().A[0],中A[0]是干啥的]
(https://ask.csdn.net/questions/714188)

最后,我们会看到下面这个效果图


数据点与拟合直线

几乎所有的数据集都能用以上这个方法建立模型,但是如何比较预测数据yhat与真实数据y的匹配程度呢?我们可以用这两个值的相关系数来评价。
在Python中,NumPy库提供了相关系数的计算方法:可以通过命令corrcoef(yEstimate, yActual)来计算预测值和真实值的相关性。下面我们就在前面的数据集上做个实验。

测试函数

import matplotlib.pyplot as plt
from numpy import *
import regression

xArr,yArr = regression.loadDataSet('ex0.txt')   #xArr二维列表,yArr是一维列表
ws = regression.standRegress(xArr, yArr)     #求回归系数ws
xMat = mat(xArr)    #转换为矩阵
yMat = mat(yArr)
yHat = xMat*ws
print(corrcoef(yHat.T, yMat))

该矩阵包含所有两两组合的相关系数。可以看到,对角线上的数据是1.0,因为yMat和自己的匹配是最完美的,而YHat和yMat的相关系数为0.98。

数据点与拟合直线

我们从以上图片可以看出,数据点走向不应该是一条直线,我们按上述方法找到的最佳拟合直线也是欠拟合的,因此我们还应该进一步细化直线走势——局部加权线性函数

局部加权线性回归

线性回归的一个问题是有可能出现欠拟合现象,因为它求的是具有最小均方误差的无偏估计什么是无偏估计?
模型欠拟合将不会获得好的预测效果,如果我们允许引入一些偏差,可能会更进一步降低均方误差。

引入局部加权线性回归LWLR

给预测点附近的每个点一个权重,在这个子集上基于最小均方误差来进行普通的回归

w的计算公式,其中W是权重,我们可以高斯核

k的值对训练回归模型的影响

regression.py

from numpy import *


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 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,can not 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

在这里解释一些函数的意义:
python: numpy--函数 shape和eye用法
numpy库函数:zeros用法

main.py

import regression
from numpy import *
import matplotlib.pyplot as plt

xArr, yArr = regression.loadDataSet('ex0.txt')
yHat = regression.lwlrTest(xArr, xArr, yArr, 0.003)
xMat = mat(xArr)
srtInd = xMat[:, 1].argsort(0)
xSort = xMat[srtInd][:, 0, :]
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(xSort[:, 1], yHat[srtInd])
ax.scatter(xMat[:, 1].flatten().A[0], mat(yArr).T.flatten().A[0], s=2, c='red')
plt.show()
k=0.01的局部加权线性回归.png

k = 1的局部加权线性回归.png

局部加权线性回归增加了计算量,对每个点的预测都必须使用整个数据集,当k = 0.01时,大多数数据点的权重为0,减少了程序的运行时间。

缩减系数来“理解”数据

如果数据的特征点比样本点还多应该怎么办?这种情况下,计算XTX会等于0,即不可逆,因此会出错。
为了解决这个问题,引入两个缩减系数的方法:

  • 岭回归(ridge regression)
  • 前向逐步回归

1 岭回归

岭回归就是在XTX上加一个lam*I,矩阵I是一个单位矩阵,lam是用户自定义的。

w计算公式

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

def ridgeRegres(xMat, yMat, lam=0.2):
    xTx = xMat.T * xMat
    denom = xTx + eye(shape(xMat)[1]) * lam
    if 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 = mat(xArr)
    yMat = mat(yArr).T
    yMean = mean(yMat, 0)
    yMat = yMat - yMean  # to eliminate X0 take mean off of Y
    # regularize X's
    xMeans = mean(xMat, 0)  # calc mean then subtract it off
    xVar = var(xMat, 0)  # calc variance of Xi then divide by it
    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

main

import regression
from numpy import *
import matplotlib.pyplot as plt

abX, abY = regression.loadDataSet('abalone.txt')
ridgeWeights = regression.ridgeTest(abX, abY)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(ridgeWeights)
plt.show()

运行之后的效果图如下:


30个不同lamda对应的回归系数,回归系数与log(lamda)的关系

在最左边,lam最小时,得到所有系数的原始值,而在最右边,系数全部缩减为0,在中间某部分的某值将会取得最好的预测效果,为了找到最佳参数值,还需要交叉验证。

2 前向逐步回归

lasso法对回归系数做了限定,对应的约束条件如下:


lasso对系数的限定

在lam足够小的时候,一些系数会被迫缩减为0,这个特性可以帮助我们理解数据,这个算法的计算复杂度相当高,我们采取一个更简单的办法来得到结果——前向逐步回归。
前向逐步回归更简单,属于贪心算法,每一步都尽可能减少误差。一开始,所有的权重都设置为1,然后每一步所做的决策是对某个权重增加或者减少一个很小的值。
逐步线性回归算法的实际好处在于它可以帮助人们理解现有的模型并做出改进。构建了这个模型之后,可以运行该算法找到重要的特征,可以及时停止对不重要特征的收集。如果用于测试,该算法每100次迭代后,就可以构建一个模型,可以使用10折交叉验证的方法比较这些模型,最终选择使误差最小的模型。
当应用缩减方法时,模型也就增加了偏差,与此同时却减小了模型的方差。

3 权衡偏差与方差

  • 误差:模型和测量值之间的差异
    我们在建立模型时,可能会对复杂的过程进行简化,这将导致在模型和测量值之间出现噪声或者误差。


    偏差方差折中与测试误差及训练误差的关系

我们已经知道,如果降低核的大小,训练误差将缩小。
一般认为,测试误差及训练误差由三部分组成:偏差、测量误差和随机噪声。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容