机器学习-回归

这里的回归是指线性回归,也存在非线性回归,不在这篇文章的范围内。

回归与分类一样,最终目的都是预测目标值。回归用于预测连续型变量,而分类用于预测离散型变量。回归是统计学中最有力的工具之一。

先解释几个容易混淆的概念:

拟合:根据离散的数据点找到一个近似函数,该函数能够大致的反应出原数据点的分布规律(不一定通过原数据点),通过该函数能够预测原数据点区间外的未知数据。找到该函数的过程称为拟合。

插值:根据离散的数据点找到一个最佳的函数,该函数能够反应出原数据点在此区间的分布规律(需要通过原数据点)。通过该函数能够预测原数据点区间内的其它未知数据,但无法预测原数据点区间外的数据,因为误差非常大。找到该函数的过程称为插值。

逼近:给定一个复杂的函数(不是数据点),求解另一个简单的函数(可以为多项式函数)使得其可以非常接近原来的复杂函数。找到该简单函数的过程称为逼近。

回归:回归是统计学中的一种技术,用于分析数据与数据之间的关系。可以通过拟合的方式找到数据的关系,也可以通过局部加权线性回归,岭回归,逐步向前回归,逐步向后回归,套索回归,分析相关系数等方式来分析数据的关系。

下面这篇文章介绍了曲线的常见拟合方法:机器学习-曲线拟合,但这都是基于二维平面数据,只能分析样本的一个特征。真实的场景下样本往往有很多特征,因此需要考虑在多维空间中如何做线性回归。

本文包含以下内容:

  1. 线性回归找到最佳拟合直线
  2. 局部加权线性回归
  3. 缩减系数来“理解”数据

部分内容引用自《Machine Learning in Action》


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

假设所有样本的特征存放在矩阵 中,向量 y 表示每个样本的函数值。现在需要找到一个回归系数向量 w ,使得样本的真实值和预测值之间的平方误差最小(最小二乘法),即下面的值最小:

根据最小二乘法原理,可以解出 w 的表达式:

注意,这里要求矩阵 可逆,否则无法得到 w。如果样本点个数小于特征个数,该矩阵将不可逆,不能用上面公式计算,后面会讨论这种场景。

准备以下数据:

注:第一列为固定值,便于计算,对结果无影响,第二列为特征值,第三列为函数值。

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

新建模块 load_data_set.py 用于加载上面数据:

def load_data_set(file_name):
    num_feat = len(open(file_name).readline().split('\t')) - 1
    data_mat = [];
    label_mat = []
    fr = open(file_name)
    for line in fr.readlines():
        line_arr = []
        cur_line = line.strip().split('\t')
        for i in range(num_feat):
            line_arr.append(float(cur_line[i]))
        data_mat.append(line_arr)
        label_mat.append(float(cur_line[-1]))
    return data_mat, label_mat


if __name__ == '__main__':
    data_arr, label_arr = load_data_set('ex0.txt')
    print(data_arr[0:2])
    print(label_arr[0:2])

新建模块 least_squares.py 用于做直线拟合:

import numpy as np
import matplotlib.pyplot as plt
import regression.load_data_set as lds


def stand_regres(x_arr, y_arr):
    x_mat = np.mat(x_arr)
    y_mat = np.mat(y_arr).T
    x_Tx = x_mat.T * x_mat
    if np.linalg.det(x_Tx) == 0.0:
        print("This matrix is singular, cannot do inverse.")
        return
    ws = x_Tx.I * (x_mat.T * y_mat)
    return ws


def figure(x_mat, y_mat, ws):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(x_mat[:, 1].flatten().A[0], y_mat.T[:, 0].flatten().A[0])

    x_copy = x_mat.copy()
    x_copy.sort(0)
    y_hat = x_copy * ws
    ax.plot(x_copy[:, 1], y_hat, 'r')

    plt.show()


if __name__ == "__main__":
    x_arr, y_arr = lds.load_data_set('ex0.txt')
    ws = stand_regres(x_arr, y_arr)
    print(ws)
    y_hat = np.mat(x_arr) * ws
    print(np.corrcoef(y_hat.T, np.mat(y_arr)))
    figure(np.mat(x_arr), np.mat(y_arr), ws)

输出结果:

D:\work\python_workspace\machine_learning\venv\Scripts\python.exe D:/work/python_workspace/machine_learning/regression/least_squares.py
[[3.00774324]
 [1.69532264]]
[[1.         0.98647356]
 [0.98647356 1.        ]]

图像:

局部加权线性回归

该方法(Locally Weighted Linerar Regression,LWLR)的思想是给待预测点附近的点赋予一定的权重,离预测点越近的点其权重越大,越远则权重越小。这样,回归系数变成以下形式:

其中,就是权重矩阵。LWLR使用核来对附近的点赋予权重,常用的是高斯核,

其中 是一个需要指定的系数,用于控制权重的大小。

代码:

import matplotlib.pyplot as plt
import numpy as np

import regression.load_data_set as lds


def lwlr(test_point, x_arr, y_arr, k=1.0):
    x_mat = np.mat(x_arr)
    y_mat = np.mat(y_arr).T
    m = np.shape(x_mat)[0]
    weights = np.mat(np.eye(m))
    for j in range(m):
        diff_mat = test_point - x_mat[j, :]
        weights[j, j] = np.exp(diff_mat * diff_mat.T / (-2.0 * k ** 2))
    x_Tx = x_mat.T * (weights * x_mat)
    if np.linalg.det(x_Tx) == 0.0:
        print("This matrix is singular, cannot do inverse.")
        return
    ws = x_Tx.I * (x_mat.T * (weights * y_mat))
    return test_point * ws


def lwlr_test(test_arr, x_arr, y_arr, k=1.0):
    m = np.shape(test_arr)[0]
    y_hat = np.zeros(m)
    for i in range(m):
        y_hat[i] = lwlr(test_arr[i], x_arr, y_arr, k)
    return y_hat


def figure(x_mat, y_mat, y_hat):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(x_mat[:, 1].flatten().A[0], y_mat.T[:, 0].flatten().A[0], s=4)

    srt_index = x_mat[:, 1].argsort(0)
    x_sort = x_mat[srt_index][:, 0, :]
    ax.plot(x_sort[:, 1], y_hat[srt_index], 'r')

    plt.show()


if __name__ == "__main__":
    x_arr, y_arr = lds.load_data_set('ex0.txt')
    # Change k to 1, 0.01 and 0.003 to see the chart
    y_hat = lwlr_test(x_arr, x_arr, y_arr, k = 0.01)
    # print(y_hat)
    x_mat = np.mat(x_arr)
    y_mat = np.mat(y_arr)
    figure(x_mat, y_mat, y_hat)

图像:

上面图像是参数 k = 0.01的场景,下面是 k = 1 和 0.003 的图像,

可以看出,k为1时就是一条直线,和普通的线性拟合一样,k为0.003时,曲线不太光滑,多度拟合。所以,k 为 0.01时的图像应该是最好的拟合图像。 因此,调整参数 k 是非常关键的。

实例:预测鲍鱼年龄

准备数据集(该数据集很多,只保留前面部分),该样本有8个特征:

1	0.455	0.365	0.095	0.514	0.2245	0.101	0.15	15
1	0.35	0.265	0.09	0.2255	0.0995	0.0485	0.07	7
-1	0.53	0.42	0.135	0.677	0.2565	0.1415	0.21	9
1	0.44	0.365	0.125	0.516	0.2155	0.114	0.155	10
0	0.33	0.255	0.08	0.205	0.0895	0.0395	0.055	7
0	0.425	0.3	0.095	0.3515	0.141	0.0775	0.12	8
-1	0.53	0.415	0.15	0.7775	0.237	0.1415	0.33	20
-1	0.545	0.425	0.125	0.768	0.294	0.1495	0.26	16
1	0.475	0.37	0.125	0.5095	0.2165	0.1125	0.165	9
-1	0.55	0.44	0.15	0.8945	0.3145	0.151	0.32	19
-1	0.525	0.38	0.14	0.6065	0.194	0.1475	0.21	14
1	0.43	0.35	0.11	0.406	0.1675	0.081	0.135	10
......

代码:

import numpy as np
import regression.load_data_set as lds
import regression.lwlr as lwlr
import regression.least_squares as ls


def rssError(y_arr, y_hat_arr):
    return ((y_arr - y_hat_arr) ** 2).sum()


if __name__ == "__main__":
    ab_x, ab_y = lds.load_data_set('abalone.txt')
    y_hat01 = lwlr.lwlr_test(ab_x[0:99], ab_x[0:99], ab_y[0:99], 0.1)
    y_hat1 = lwlr.lwlr_test(ab_x[0:99], ab_x[0:99], ab_y[0:99], 1)
    y_hat10 = lwlr.lwlr_test(ab_x[0:99], ab_x[0:99], ab_y[0:99], 10)
    print(rssError(ab_y[0:99], y_hat01.T))
    print(rssError(ab_y[0:99], y_hat1.T))
    print(rssError(ab_y[0:99], y_hat10.T))
    print()
    y_hat01 = lwlr.lwlr_test(ab_x[100:199], ab_x[0:99], ab_y[0:99], 0.1)
    y_hat1 = lwlr.lwlr_test(ab_x[100:199], ab_x[0:99], ab_y[0:99], 1)
    y_hat10 = lwlr.lwlr_test(ab_x[100:199], ab_x[0:99], ab_y[0:99], 10)
    print(rssError(ab_y[100:199], y_hat01.T))
    print(rssError(ab_y[100:199], y_hat1.T))
    print(rssError(ab_y[100:199], y_hat10.T))
    print()
    ws = ls.stand_regres(ab_x[0:99], ab_y[0:99])
    y_hat = np.mat(ab_x[100:199]) * ws
    print(rssError(ab_y[100:199], y_hat.T.A))

输出:

D:\work\python_workspace\machine_learning\venv\Scripts\python.exe D:/work/python_workspace/machine_learning/regression/abalone_test.py
56.78868743050092
429.89056187038
549.1181708827924

57913.51550155911
573.5261441895982
517.5711905381903

518.6363153245542

Process finished with exit code 0

可以看出,上面的代码可以适用于多个特征的样本数据集,虽然此时无法画出图像,但我们能准确的预测未知数据。

缩减系数来“理解”数据

前面提到当样本个数小于特征个数,则矩阵不可逆,无法用前面的公式来计算拟合系数。我们可以通过岭回归的方式增加一个使得矩阵  可逆,其中是单位矩阵。这时,回归系数变成如下形式:

在使用岭回归时需要对样本数据做标准化处理,具体的做法就是所有特征值都减去各自的平均值再除以方差。

还有一些方法。如lasso,LAR,PCA等与岭回归一样,不仅可以提高预测精度,还可以解释回归系数。

 

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页