回归

线性回归

原理:

  • 寻找一组最优参数来拟合数据

优点

  • 结果易于理解,计算上不复杂

缺点

  • 对非线性的数据拟合不好

适用数据类型

  • 数值型和标称型数据
加载数据
import numpy as np
def loadDataSet(fileName):
    dataList = []; labelList = []
    fr = open(fileName)
    lenOfLine = len(fr.readline().strip().split())
    for line in fr.readlines():
        lineList = line.strip().split()
        curLine =[]
        for i in range(len(lineList)-1):
            curLine.append(float(lineList[i]))
        dataList.append(curLine)
        labelList.append(float(lineList[-1]))
    return dataList,labelList
dataList,labelList = loadDataSet('../../Reference Code/Ch08/ex0.txt')

标准回归函数

def standRegres(xArr,yArr):
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    xTx = xMat.T*xMat #矩阵乘法
    if np.linalg.det(xTx) == 0: #行列式为0
        print('This matrix is singular, cannot do inverse') #奇异矩阵,不可逆
        return
    else:
        ws = xTx.I*(xMat.T*yMat)
    return ws
ws = standRegres(dataList,labelList)
ws
matrix([[3.00681047],
        [1.69667188]])

画图可视化

import matplotlib.pyplot as plt
def data2show(dataList,labelList,ws):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.grid()
    #原始数据分布:x,y都是在一个list
    x = np.mat(dataList)[:,1].T.A[0]#.A是将matrix转换成array
    y = np.mat(labelList).A[0]
    ax.scatter(x,y,s=10,label='Raw Data') 

    #拟合的直线
    xCopy = np.mat(dataList).copy()
    yHat = xCopy*ws
    ax.plot(xCopy[:,1],yHat,c='r',label='Line Regression')
    
    ax.set_xlim((0,1))
    plt.legend()
    plt.show()
data2show(dataList,labelList,ws)
output_9_0.png

计算预测值yHat与真是值y的匹配程度:相关系数

xCopy = np.mat(dataList).copy()
yHat = xCopy*ws
y = np.mat(labelList)
print('预测值和真实值的相关系数矩阵为:\n' ,np.corrcoef(yHat.T,y))
预测值和真实值的相关系数矩阵为:
 [[1.        0.9863846]
 [0.9863846 1.       ]]

局部加权线性回归(Locally Weighted Linear Regression,LWLR)

  • 线性回归可能出现欠拟合,我们给待预测点附近的每个点赋予一定的权重,如使用高斯核来作为权重,随着样本点与待预测点的距离的递增,权重将以指数级递减。
  • 缺点:增加了计算量,对每一个点做预测时都要使用整个数据集
对单一样本使用LWLR

def lwlr(testPoint,xArr,yArr,k=1.0):
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    m = xMat.shape[0]
    weights = np.mat(np.eye((m))) #初始化,每个样本赋予权重为1
    for j in range(m):#遍历每一个样本
        diffMat = testPoint - xMat[j,:] 
        weights[j,j] = np.exp((diffMat*diffMat.T)/(-2*k**2))
    xTx = xMat.T*(weights*xMat) #矩阵乘法
    if np.linalg.det(xTx) == 0: #行列式为0
        print('This matrix is singular, cannot do inverse') #奇异矩阵,不可逆
        return
    else:
        ws = xTx.I*(xMat.T*(weights*yMat))
    yHat = testPoint*ws
    return yHat
yHat = lwlr(dataList[0],dataList,labelList,k=0.001)
print('预测值',yHat.A[0,0])
print('真实值:',labelList[0])
预测值 3.772513220268465
真实值: 3.816464
遍历所有样本使用LWLR
def lwlrTest(testArr,xArr,yArr,k=1.0):
    m = np.shape(testArr)[0]
    yHat = np.zeros(m)
    for i in range(m): #遍历所有测试样本,使用lwlr
        yHat[i] = lwlr(testArr[i],xArr,yArr,k)
    return yHat
yHat_k1 = lwlrTest(dataList,dataList,labelList,k=1.0)
yHat_k2 = lwlrTest(dataList,dataList,labelList,k=0.01)
yHat_k3 = lwlrTest(dataList,dataList,labelList,k=0.003)
#要画出拟合出来的直线,首先对xArr[:,1]排序,用plot一个个直线将xArr[:,1]和yHat连接起来构成拟合直线
import matplotlib.pyplot as plt
xArr = np.array(dataList)
yArr = np.array(labelList)
sortIndex = xArr[:,1].argsort(0) #按列排序
fig = plt.figure(figsize=(6,8))

#k=1.0,是一条直线,相当于线性回归
ax = fig.add_subplot(311)
ax.grid()
ax.scatter(xArr[:,1],yArr,s=5)
ax.plot(xArr[:,1][sortIndex],yHat_k1[sortIndex],c='r')
ax.legend(("prediction", "data"))
ax.set_xlim((0,1))
ax.set_title('k=1.0')

#k=0.1
ax = fig.add_subplot(312)
ax.grid()
ax.scatter(xArr[:,1],yArr,s=5,label='data')
ax.plot(xArr[:,1][sortIndex],yHat_k2[sortIndex],c='r')
ax.legend(("prediction", "data"))
ax.set_xlim((0,1))
ax.set_title('k=0.1')

#k=0.003
ax = fig.add_subplot(313)
# ax.grid()
ax.scatter(xArr[:,1],yArr,s=5)
ax.plot(xArr[:,1][sortIndex],yHat_k3[sortIndex],c='r')
ax.legend(("prediction", "data"))
ax.set_xlim((0,1))
ax.set_title('k=0.03')

plt.tight_layout()
plt.show()
output_19_0.png
  • k=1,所有数据等权重,相当于线性回归
  • k=0.1,效果较好
  • k=0.03 仅有很少的局部样本用于训练,考虑了太多噪声,过拟合

预测鲍鱼的年龄

#定义误差函数
def rssError(yArr,yHatArr):
    return ((yArr - yHatArr)**2).sum()/len(yHatArr)
训练
abX,abY = loadDataSet('../../Reference Code/Ch08/abalone.txt')
yHat_01 = lwlrTest(abX[0:99],abX[0:99],abY[0:99],0.1)
yHat_1 = lwlrTest(abX[0:99],abX[0:99],abY[0:99],1)
yHat_10 = lwlrTest(abX[0:99],abX[0:99],abY[0:99],10)
error_01 = rssError(abY[0:99],yHat_01)
error_1 = rssError(abY[0:99],yHat_1)
error_10 = rssError(abY[0:99],yHat_10)
print('k=0.1,训练集均方误差:',error_01)
print('k=1,训练集均方误差:',error_1)
print('k=10,训练集均方误差:',error_10)
k=0.1,训练集均方误差: 0.5336662333518674
k=1,训练集均方误差: 3.9193270598039254
k=10,训练集均方误差: 5.155636180982812
测试
yHat_01 = lwlrTest(abX[100:199],abX[0:99],abY[0:99],0.1)
yHat_1 = lwlrTest(abX[100:199],abX[0:99],abY[0:99],1)
yHat_10 = lwlrTest(abX[100:199],abX[0:99],abY[0:99],10)
error_01 = rssError(abY[100:199],yHat_01)
error_1 = rssError(abY[100:199],yHat_1)
error_10 = rssError(abY[100:199],yHat_10)
print('k=0.1,测试集均方误差:',error_01)
print('k=1,测试集均方误差:',error_1)
print('k=10,测试集均方误差:',error_10)
k=0.1,测试集均方误差: 253.07098763356757
k=1,测试集均方误差: 6.096745426262262
k=10,测试集均方误差: 5.6509772437177395
使用线性回归
ws = standRegres(abX[0:99],abY[0:99])
xCopy = np.mat(abX[0:99]).copy()
yHat = xCopy*ws
error = rssError(abY[0:99],yHat.T.A[0])
print('训练集均方误差:',error)

xCopy = np.mat(abX[100:199]).copy()
yHat = xCopy*ws
error = rssError(abY[100:199],yHat.T.A[0])
print('测试集均方误差:',error)
训练集均方误差: 5.175439324394303
测试集均方误差: 5.663372502296616
  • 线性回归达到了局部加权线性回归(k=10)的效果

岭回归

#定义岭回归的回归系数公式
def ridgeRegres(xMat,yMat,lam=0.2):
    xTx = xMat.T*xMat
    denom = xTx + np.eye(xMat.shape[1])*lam
    if np.linalg.det(denom) == 0:
        print('Thi matrix is singular, cannot do inverse')
        return
    ws = denom.I*(xMat.T*yMat)
    return ws

#标准化
def standar(xMat,yMat):
    yMean = np.mean(yMat,0) #按列求平均
    yMat = yMat - yMean #书本这里没有除以方差
#     yMat = (yMat - yMean)/np.var(yMat)
    xMean = np.mean(xMat,0)#按列求平均
    xVar = np.var(xMat,0)#按列求方差
    xMat = (xMat - xMean)/xVar
    return xMat,yMat

#搜索最优lamda
def searchLamda(xMat,yMat):
    numTestPts = 30
    n = xMat.shape[1]
    wMat = np.zeros((numTestPts,n))
    for i in range(numTestPts):
        ws = ridgeRegres(xMat,yMat,np.exp(i-10))
        wMat[i,:] = ws.T
    return wMat
无标准化
#加载数据并转换为mat形式
abX,abY = loadDataSet('../../Reference Code/Ch08/abalone.txt')
xMat = np.mat(abX);yMat = np.mat(abY).T
#搜索lamda
wMat = searchLamda(xMat,yMat)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(wMat) #行index为x轴,列的值为y
ax.set_xlabel('log(lambda)')
plt.show()
output_33_0.png
有标准化
#加载数据并转换为mat形式
abX,abY = loadDataSet('../../Reference Code/Ch08/abalone.txt')
xMat = np.mat(abX);yMat = np.mat(abY).T
xMat,yMat=standar(xMat,yMat) #标准化
#搜索lamda
wMat = searchLamda(xMat,yMat)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(wMat) #行index为x轴,列的值为y
ax.set_xlabel('log(lambda)')
plt.show()
output_35_0.png
  • 普通线性回归不用标准化
  • 岭回归和Lasso需要标准化
前向逐步回归
def stageWise(xMat,yMat,eps =0.01,numIter=100):
    m,n = xMat.shape
    returnMat = np.zeros((numIter,n))
    ws = np.zeros((n,1));wsBest = ws.copy()
    for i in range(numIter): #迭代100次,得到100个ws
#         print(ws.T)
        lowestErr = np.inf #初始化误差为无穷大
        for j in range(n): #遍历每一个特征
            for sign in [-1,1]: #每个特征增加或者减少
                wsTest = ws.copy()
                wsTest[j] += eps*sign #第j个特征,增加或者减少一个步长
                
                #计算误差
                yTest = xMat * wsTest
                rssE = rssError(yMat.A,yTest.A)
                
                #保存j特征下,误差最小的ws,和误差
                if rssE < lowestErr: 
                    lowestErr = rssE
                    wsBest = wsTest
                    
            #保存所有特征下误差最小对应的ws
        ws = wsBest.copy()
        returnMat[i,:] = ws.T
    return returnMat
#加载数据并转换为mat形式
abX,abY = loadDataSet('../../Reference Code/Ch08/abalone.txt')
xMat = np.mat(abX);yMat = np.mat(abY).T
xMat,yMat=standar(xMat,yMat) #标准化
returnMat=stageWise(xMat,yMat,eps =0.001,numIter=5000)
returnMat
array([[ 0.   ,  0.   ,  0.   , ...,  0.   ,  0.   ,  0.   ],
       [ 0.   ,  0.   ,  0.   , ...,  0.   ,  0.   ,  0.   ],
       [ 0.   ,  0.   ,  0.   , ...,  0.   ,  0.   ,  0.   ],
       ...,
       [ 0.041, -0.01 ,  0.119, ..., -0.967, -0.106,  0.185],
       [ 0.042, -0.01 ,  0.119, ..., -0.967, -0.106,  0.185],
       [ 0.041, -0.01 ,  0.119, ..., -0.967, -0.106,  0.185]])
对比普通线性回归
dataList = xMat.tolist();labelList = yMat.T.tolist()
ws = standRegres(dataList,labelList)
ws.T
matrix([[ 0.04166622, -0.02188497,  0.13114956,  0.02087776,  2.22254154,
         -0.99875234, -0.11703624,  0.16645722]])
  • 逐步线性回归算法(numIter=5000,eps=0.001)与常规的最小二乘法效果类似
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(returnMat) #行index为x轴,列的值为y
ax.set_xlabel('log(lambda)')
plt.show()
output_43_0.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容