机器学习笔记11-线性回归(上)

一、线性回归

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

应该怎么从一大堆数据里求出回归方程呢?假定输入数据存放在矩阵X中,结果存放在向量y中:
在这里插入图片描述
而回归系数存放在向量w中:
在这里插入图片描述那么对于给定的数据x1,即矩阵X的第一列数据,预测结果u1将会通过如下公式给出:
在这里插入图片描述现在的问题是,手里有数据矩阵X和对应的标签向量y,怎么才能找到w呢?一个常用的方法就是找出使误差最小的w。这里的误差是指预测u值和真实y值之间的差值,使用该误差的简单累加将使得正差值和负差值相互抵消,所以我们采用平方误差。
平方误差和可以写做:
在这里插入图片描述用矩阵表示还可以写做:
0为啥能这么变化,记住一个前提:若x为向量,则默认x为列向量,x^T为行向量。将上述提到的数据矩阵X和标签向量y带进去,就知道为何这么变化了。

在继续推导之前,我们要先明确一个目的:找到w,使平方误差和最小。因为我们认为平方误差和越小,说明线性回归拟合效果越好。

现在,我们用矩阵表示的平方误差和对w进行求导:
在这里插入图片描述令上述公式等于0,得到:
在这里插入图片描述w上方的小标记表示,这是当前可以估计出的w的最优解。从现有数据上估计出的w可能并不是数据中的真实w值,所以这里使用了一个”帽”符号来表示它仅是w的一个最佳估计。

值得注意的是,上述公式中包含逆矩阵,也就是说,这个方程只在逆矩阵存在的时候使用,也即是这个矩阵是一个方阵,并且其行列式不为0。

上述的最佳w求解是统计学中的常见问题,除了矩阵方法外还有很多其他方法可以解决。通过调用NumPy库里的矩阵方法,我们可以仅使用几行代码就完成所需功能。该方法也称作OLS, 意思是“普通小二乘法”(ordinary least squares)。

数据集:

1.000000	0.067732	3.176513
1.000000	0.427810	3.816464
1.000000	0.995731	4.550095
1.000000	0.738336	4.256571
1.000000	0.981083	4.560815
1.000000	0.526171	3.929515
1.000000	0.378887	3.526170
1.000000	0.033859	3.156393
1.000000	0.132791	3.110301
1.000000	0.138306	3.149813
1.000000	0.247809	3.476346
1.000000	0.648270	4.119688
1.000000	0.731209	4.282233
1.000000	0.236833	3.486582
1.000000	0.969788	4.655492
1.000000	0.607492	3.965162
1.000000	0.358622	3.514900
1.000000	0.147846	3.125947
1.000000	0.637820	4.094115
1.000000	0.230372	3.476039
1.000000	0.070237	3.210610
1.000000	0.067154	3.190612
1.000000	0.925577	4.631504
1.000000	0.717733	4.295890
1.000000	0.015371	3.085028
1.000000	0.335070	3.448080
1.000000	0.040486	3.167440
1.000000	0.212575	3.364266
1.000000	0.617218	3.993482
1.000000	0.541196	3.891471
1.000000	0.045353	3.143259
1.000000	0.126762	3.114204
1.000000	0.556486	3.851484
1.000000	0.901144	4.621899
1.000000	0.958476	4.580768
1.000000	0.274561	3.620992
1.000000	0.394396	3.580501
1.000000	0.872480	4.618706
1.000000	0.409932	3.676867
1.000000	0.908969	4.641845
1.000000	0.166819	3.175939
1.000000	0.665016	4.264980
1.000000	0.263727	3.558448
1.000000	0.231214	3.436632
1.000000	0.552928	3.831052
1.000000	0.047744	3.182853
1.000000	0.365746	3.498906
1.000000	0.495002	3.946833
1.000000	0.493466	3.900583
1.000000	0.792101	4.238522
1.000000	0.769660	4.233080
1.000000	0.251821	3.521557
1.000000	0.181951	3.203344
1.000000	0.808177	4.278105
1.000000	0.334116	3.555705
1.000000	0.338630	3.502661
1.000000	0.452584	3.859776
1.000000	0.694770	4.275956
1.000000	0.590902	3.916191
1.000000	0.307928	3.587961
1.000000	0.148364	3.183004
1.000000	0.702180	4.225236
1.000000	0.721544	4.231083
1.000000	0.666886	4.240544
1.000000	0.124931	3.222372
1.000000	0.618286	4.021445
1.000000	0.381086	3.567479
1.000000	0.385643	3.562580
1.000000	0.777175	4.262059
1.000000	0.116089	3.208813
1.000000	0.115487	3.169825
1.000000	0.663510	4.193949
1.000000	0.254884	3.491678
1.000000	0.993888	4.533306
1.000000	0.295434	3.550108
1.000000	0.952523	4.636427
1.000000	0.307047	3.557078
1.000000	0.277261	3.552874
1.000000	0.279101	3.494159
1.000000	0.175724	3.206828
1.000000	0.156383	3.195266
1.000000	0.733165	4.221292
1.000000	0.848142	4.413372
1.000000	0.771184	4.184347
1.000000	0.429492	3.742878
1.000000	0.162176	3.201878
1.000000	0.917064	4.648964
1.000000	0.315044	3.510117
1.000000	0.201473	3.274434
1.000000	0.297038	3.579622
1.000000	0.336647	3.489244
1.000000	0.666109	4.237386
1.000000	0.583888	3.913749
1.000000	0.085031	3.228990
1.000000	0.687006	4.286286
1.000000	0.949655	4.628614
1.000000	0.189912	3.239536
1.000000	0.844027	4.457997
1.000000	0.333288	3.513384
1.000000	0.427035	3.729674
1.000000	0.466369	3.834274
1.000000	0.550659	3.811155
1.000000	0.278213	3.598316
1.000000	0.918769	4.692514
1.000000	0.886555	4.604859
1.000000	0.569488	3.864912
1.000000	0.066379	3.184236
1.000000	0.335751	3.500796
1.000000	0.426863	3.743365
1.000000	0.395746	3.622905
1.000000	0.694221	4.310796
1.000000	0.272760	3.583357
1.000000	0.503495	3.901852
1.000000	0.067119	3.233521
1.000000	0.038326	3.105266
1.000000	0.599122	3.865544
1.000000	0.947054	4.628625
1.000000	0.671279	4.231213
1.000000	0.434811	3.791149
1.000000	0.509381	3.968271
1.000000	0.749442	4.253910
1.000000	0.058014	3.194710
1.000000	0.482978	3.996503
1.000000	0.466776	3.904358
1.000000	0.357767	3.503976
1.000000	0.949123	4.557545
1.000000	0.417320	3.699876
1.000000	0.920461	4.613614
1.000000	0.156433	3.140401
1.000000	0.656662	4.206717
1.000000	0.616418	3.969524
1.000000	0.853428	4.476096
1.000000	0.133295	3.136528
1.000000	0.693007	4.279071
1.000000	0.178449	3.200603
1.000000	0.199526	3.299012
1.000000	0.073224	3.209873
1.000000	0.286515	3.632942
1.000000	0.182026	3.248361
1.000000	0.621523	3.995783
1.000000	0.344584	3.563262
1.000000	0.398556	3.649712
1.000000	0.480369	3.951845
1.000000	0.153350	3.145031
1.000000	0.171846	3.181577
1.000000	0.867082	4.637087
1.000000	0.223855	3.404964
1.000000	0.528301	3.873188
1.000000	0.890192	4.633648
1.000000	0.106352	3.154768
1.000000	0.917886	4.623637
1.000000	0.014855	3.078132
1.000000	0.567682	3.913596
1.000000	0.068854	3.221817
1.000000	0.603535	3.938071
1.000000	0.532050	3.880822
1.000000	0.651362	4.176436
1.000000	0.901225	4.648161
1.000000	0.204337	3.332312
1.000000	0.696081	4.240614
1.000000	0.963924	4.532224
1.000000	0.981390	4.557105
1.000000	0.987911	4.610072
1.000000	0.990947	4.636569
1.000000	0.736021	4.229813
1.000000	0.253574	3.500860
1.000000	0.674722	4.245514
1.000000	0.939368	4.605182
1.000000	0.235419	3.454340
1.000000	0.110521	3.180775
1.000000	0.218023	3.380820
1.000000	0.869778	4.565020
1.000000	0.196830	3.279973
1.000000	0.958178	4.554241
1.000000	0.972673	4.633520
1.000000	0.745797	4.281037
1.000000	0.445674	3.844426
1.000000	0.470557	3.891601
1.000000	0.549236	3.849728
1.000000	0.335691	3.492215
1.000000	0.884739	4.592374
1.000000	0.918916	4.632025
1.000000	0.441815	3.756750
1.000000	0.116598	3.133555
1.000000	0.359274	3.567919
1.000000	0.814811	4.363382
1.000000	0.387125	3.560165
1.000000	0.982243	4.564305
1.000000	0.780880	4.215055
1.000000	0.652565	4.174999
1.000000	0.870030	4.586640
1.000000	0.604755	3.960008
1.000000	0.255212	3.529963
1.000000	0.730546	4.213412
1.000000	0.493829	3.908685
1.000000	0.257017	3.585821
1.000000	0.833735	4.374394
1.000000	0.070095	3.213817
1.000000	0.527070	3.952681
1.000000	0.116163	3.129283

第一列都为1.0,即x0。第二列为x1,即x轴数据。第三列为x2,即y轴数据。首先绘制下数据,看下数据分布。编写代码如下:

#!/user/bin/env python
# -*- coding:utf-8 -*-
#@Time  : 2020/3/22 11:48
#@Author: fangyuan
#@File  : 线性回归最佳拟合直线.py

import matplotlib.pyplot as plt
import numpy as np

def loadDataSet(filename):
    numFeat = len(open(filename).readline().split('\t')) - 1
    xArr = [];yArr = []
    fr = open(filename)
    for line in fr.readlines():
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        xArr.append(lineArr)
        yArr.append(float(curLine[-1]))
    return xArr,yArr

def plotDataSet():
    xArr,yArr = loadDataSet('ex0')
    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)
    ax.scatter(xcord,ycord,s = 20,c = 'blue',alpha = .5)
    plt.title('DataSet')
    plt.xlabel('X')
    plt.show()

if __name__ == '__main__':
    plotDataSet()

在这里插入图片描述通过可视化数据,我们可以看到数据的分布情况。接下来,让我们根据上文中推导的回归系数计算方法,求出回归系数向量,并根据回归系数向量绘制回归曲线,编写代码如下:

#!/user/bin/env python
# -*- coding:utf-8 -*-
#@Time  : 2020/3/22 11:48
#@Author: fangyuan
#@File  : 线性回归最佳拟合直线.py

import matplotlib.pyplot as plt
import numpy as np

def loadDataSet(filename):
    numFeat = len(open(filename).readline().split('\t')) - 1
    xArr = [];yArr = []
    fr = open(filename)
    for line in fr.readlines():
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        xArr.append(lineArr)
        yArr.append(float(curLine[-1]))
    return xArr,yArr

def standRegres(xArr,yArr):
    """
    @param xArr: x数据集
    @param yArr: y数据集
    @return: 回归系数
    """
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    # 根据文中推导的公式计算回归系数
    xTx = xMat.T * xMat
    if np.linalg.det(xTx) == 0.0:
        print("矩阵为奇异矩阵,不能求逆")
        return
    ws = xTx.I * (xMat.T*yMat)
    return ws

# def plotDataSet():
# #     xArr,yArr = loadDataSet('ex0')
# #     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)
# #     ax.scatter(xcord,ycord,s = 20,c = 'blue',alpha = .5)
# #     plt.title('DataSet')
# #     plt.xlabel('X')
# #     plt.show()

def plotRegression():
    # 加载数据集
    xArr,yArr = loadDataSet('ex0')
    # 计算回归系数
    ws = standRegres(xArr,yArr)
    # 创建xMat矩阵
    xMat = np.mat(xArr)
    # 创建yMat矩阵
    yMat = np.mat(yArr)
    # 深拷贝xMat矩阵
    xCopy = xMat.copy()
    # 排序
    xCopy.sort(0)
    # 计算对应的y值
    yHat = xCopy * ws
    fig = plt.figure()
    # 添加subplot
    ax = fig.add_subplot(111)
    # 绘制回归曲线
    ax.plot(xCopy[:,1],yHat,c = 'red')
    # 绘制样本点
    ax.scatter(xMat[:,1].flatten().A[0],yMat.flatten().A[0],s = 20,c = 'blue',alpha = .5)
    # 绘制title
    plt.title('DataSet')
    plt.xlabel('X')
    plt.show()

if __name__ == '__main__':
    plotRegression()

在这里插入图片描述如何判断拟合曲线的拟合效果的如何呢?当然,我们可以根据自己的经验进行观察,除此之外,我们还可以使用corrcoef方法,来比较预测值和真实值的相关性。编写代码如下:

#!/user/bin/env python
# -*- coding:utf-8 -*-
#@Time  : 2020/3/22 11:48
#@Author: fangyuan
#@File  : 线性回归最佳拟合直线.py

import matplotlib.pyplot as plt
import numpy as np

def loadDataSet(filename):
    numFeat = len(open(filename).readline().split('\t')) - 1
    xArr = [];yArr = []
    fr = open(filename)
    for line in fr.readlines():
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        xArr.append(lineArr)
        yArr.append(float(curLine[-1]))
    return xArr,yArr

def standRegres(xArr,yArr):
    """
    @param xArr: x数据集
    @param yArr: y数据集
    @return: 回归系数
    """
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    # 根据文中推导的公式计算回归系数
    xTx = xMat.T * xMat
    if np.linalg.det(xTx) == 0.0:
        print("矩阵为奇异矩阵,不能求逆")
        return
    ws = xTx.I * (xMat.T*yMat)
    return ws



if __name__ == '__main__':
    # 加载数据集
    xArr,yArr = loadDataSet('ex0')
    # 计算回归系数
    ws = standRegres(xArr,yArr)
    # 创建xMat矩阵
    xMat = np.mat(xArr)
    # 创建yMat矩阵
    yMat = np.mat(yArr)
    yHat = xMat * ws
    print(np.corrcoef(yHat.T,yMat))

在这里插入图片描述可以看到,对角线上的数据是1.0,因为yMat和自己的匹配是完美的,而YHat和yMat的相关系数为0.98。

最佳拟合直线方法将数据视为直线进行建模,具有十分不错的表现。数据当中似乎还存在其他的潜在模式。那么如何才能利用这些模式呢?我们可以根据数据来局部调整预测,下面就会介绍这种方法。

2 局部加权线性回归

线性回归的一个问题是有可能出现欠拟合现象,因为它求的是具有小均方误差的无偏估 计。显而易见,如果模型欠拟合将不能取得好的预测效果。所以有些方法允许在估计中引入一 些偏差,从而降低预测的均方误差。
其中的一个方法是局部加权线性回归(Locally Weighted Linear Regression,LWLR)。在该方法中,我们给待预测点附近的每个点赋予一定的权重。与kNN一样,这种算法每次预测均需要事先选取出对应的数据子集。该算法解除回归系数W的形式如下:

在这里插入图片描述其中W是一个矩阵,这个公式跟我们上面推导的公式的区别就在于W,它用来给每个店赋予权重。
LWLR使用”核”(与支持向量机中的核类似)来对附近的点赋予更高的权重。核的类型可以自由选择,最常用的核就是高斯核,高斯核对应的权重如下:

在这里插入图片描述这样我们就可以根据上述公式,编写局部加权线性回归,我们通过改变k的值,可以调节回归效果,编写代码如下:

#!/user/bin/env python
# -*- coding:utf-8 -*-
#@Time  : 2020/3/22 14:32
#@Author: fangyuan
#@File  : 线性回归局部加权.py

from matplotlib.font_manager import FontProperties
import matplotlib.pyplot as plt
import numpy as np

def loadDataSet(filename):
    numFeat = len(open(filename).readline().split('\t')) - 1
    xArr = [];yArr = []
    fr = open(filename)
    for line in fr.readlines():
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        xArr.append(lineArr)
        yArr.append(float(curLine[-1]))
    return xArr,yArr

def plotlwlrRegression():
    """
    绘制多条局部加权回归曲线
    @return:
    """
    font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc",size=14)
    # 加载数据集
    xArr,yArr = loadDataSet('ex0')
    # 根据局部加权线性回归计算yHat
    yHat_1 = lwlrTest(xArr,xArr,yArr,1.0)
    yHat_2 = lwlrTest(xArr,xArr,yArr,0.01)
    yHat_3 = lwlrTest(xArr, xArr, yArr,0.003)
    # 创建xMat和yMat矩阵
    xMat = np.mat(xArr)
    yMat = np.mat(yArr)
    # 排序,返回索引值
    srtInd = xMat[:,1].argsort(0)
    xSort = xMat[srtInd][:,0,:]
    fig,axs = plt.subplots(nrows=3,ncols=1,sharex=False,sharey=False,figsize=(10,8))
    # 绘制回归曲线
    axs[0].plot(xSort[:,1],yHat_1[srtInd],c = 'red')
    axs[1].plot(xSort[:,1],yHat_2[srtInd],c = 'red')
    axs[2].plot(xSort[:,1],yHat_3[srtInd],c = 'red')
    axs[0].scatter(xMat[:,1].flatten().A[0],yMat.flatten().A[0],s = 20,c = 'blue',alpha = .5)
    axs[1].scatter(xMat[:,1].flatten().A[0],yMat.flatten().A[0],s = 20,c = 'blue',alpha = .5)
    axs[2].scatter(xMat[:,1].flatten().A[0],yMat.flatten().A[0],s = 20,c = 'blue',alpha = .5)
    # 设置标题x轴,y轴label
    axs0_title_text = axs[0].set_title(u'局部加权回归曲线k=1.0',FontProperties=font)
    axs1_title_text = axs[1].set_title(u'局部加权回归曲线k=0.01',FontProperties=font)
    axs2_title_text = axs[2].set_title(u'局部加权回归曲线k=0.003',FontProperties=font)
    plt.setp(axs0_title_text,size=8,weight='bold',color='red')
    plt.setp(axs1_title_text,size=8,weight='bold',color='red')
    plt.setp(axs2_title_text,size=8,weight='bold',color='red')
    plt.xlabel('X')
    plt.show()

def lwlr(testPoint,xArr,yArr,k = 1.0):
    """
    函数说明:使用局部加权线性回归计算回归系数w
    @param testPoint: 测试样本点
    @param xArr: x数据集
    @param yArr:y数据集
    @param k:高斯核的k,自定义参数
    @return:回归系数
    """
    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("矩阵为奇异阵,不能求逆")
        return
    # 计算回归系数
    ws = xTx.I * (xMat.T * (weights * yMat))
    return testPoint * ws

def lwlrTest(testArr,xArr,yArr,k = 1.0):
    """
    函数说明:局部加权线性回归测试
    @param testArr: 测试数据集
    @param xArr: x数据集
    @param yArr: y数据集
    @param k: 高斯核的k,自定义参数
    @return:
    """
    # 计算测试数据集大小
    m = np.shape(testArr)[0]
    yHat = np.zeros(m)
    # 对每个样本点进行预测
    for i in range(m):
        yHat[i] = lwlr(testArr[i],xArr,yArr,k)
    return yHat

if __name__ == '__main__':
    plotlwlrRegression()

在这里插入图片描述可以看到,当k越小,拟合效果越好。但是当k过小,会出现过拟合的情况,例如k等于0.003的时候。

二、预测鲍鱼年龄

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值