【机器学习】(二)

您所在的位置:网站首页 说明方法如何判断 【机器学习】(二)

【机器学习】(二)

2024-06-13 13:18| 来源: 网络整理| 查看: 265

学习目标:

1、数据拆分:训练数据集&测试数据集

2、评价分类结果:精准度、混淆矩阵、精准率、召回率、F1 Score、ROC曲线等

3、评价回归结果:MSE、RMSE、MAE、R Squared

知识整理:

【1】

  模型训练好之后,需要评价模型的好坏,但是测试数据也是需要有对应分类结果的,这时就需要从已有数据中分出测试集和训练集。

  我们需要将原始数据中的一部分作为训练数据、另一部分作为测试数据。使用训练数据训练模型,再用测试数据看好坏。即通过测试数据判断模型好坏,然后再不断对模型进行修改。

鸢尾花数据集(简介)是UCI数据库中常用数据集。我们可以直接加载数据集,并尝试对数据进行一定探索:

iris_train_test.py:

import numpy as np from sklearn import datasets import matplotlib.pyplot as plt iris = datasets.load_iris() X = iris.data y = iris.target print(X.shape) # 输出:(150, 4) print(X.shape) # 输出:(150,) # 一般情况下我们按照0.8:0.2的比例拆分训练集与测试集 # 但是有时候我们不能简单地把前n个数据作为训练数据集,后n个作为测试数据集 # 比如数据集有序,那么取前n个数据集(可能都是同一类别)容易使测试不准确 # ****解决方案**** # 1、将X和y合并为同一个矩阵,然后对矩阵进行shuffle,之后再分解 # 2、对y的索引进行乱序,根据索引确定与X的对应关系,最后再通过乱序的索引进行赋值 # 方法一: # 使用concatenate函数进行拼接,因为传入的矩阵必须具有相同的形状 # 因此需要对label进行reshape操作,reshape(-1,1)表示行数自动计算,1列。axis=1表示纵向拼接 tempConcat = np.concatenate((X, y.reshape(-1,1)), axis=1) # 拼接好后,直接进行乱序操作 np.random.shuffle(tempConcat) # 再将shuffle后的数组使用split方法拆分 shuffle_X,shuffle_y = np.split(tempConcat, [4], axis=1) # 设置划分的比例 test_ratio = 0.2 test_size = int(len(X) * test_ratio) X_train = shuffle_X[test_size:] y_train = shuffle_y[test_size:] X_test = shuffle_X[:test_size] y_test = shuffle_y[:test_size] print(X_train.shape) print(X_test.shape) print(y_train.shape) print(y_test.shape) # 方法二: # 将x长度这么多的数,返回一个新的打乱顺序的数组 # 注意,数组中的元素不是原来的数据,而是混乱的索引 shuffle_index = np.random.permutation(len(X)) # 指定测试数据的比例 test_ratio = 0.2 test_size = int(len(X) * test_ratio) test_index = shuffle_index[:test_size] train_index = shuffle_index[test_size:] X_train = X[train_index] X_test = X[test_index] y_train = y[train_index] y_test = y[test_index] print(X_train.shape) print(X_test.shape) print(y_train.shape) print(y_test.shape)

封装train_test_split(model_selection.py):

import numpy as np def train_test_split(X, y, test_ratio=0.2, seed=None): """将矩阵X和标签y按照test_ration分割成X_train, X_test, y_train, y_test""" assert X.shape[0] == y.shape[0], \ "the size of X must be equal to the size of y" assert 0.0 = threshold 是布尔型向量,用dtype设置为int # 大于等于阈值threshold分类为1,小于为0,用这种方法得到预测值 y_predict = np.array(decision_scores >= threshold, dtype=int) # print(y_predict) # print(y_test) # print(FPR(y_test, y_predict)) # 对于每个阈值,所得到的FPR和TPR都添加到相应的队列中 fprs.append(FPR(y_test, y_predict)) tprs.append(TPR(y_test, y_predict)) # 绘制ROC曲线,x轴是fpr的值,y轴是tpr的值 plt.plot(fprs, tprs) plt.show()

    

sklearn中的ROC曲线:

from sklearn.metrics import roc_curve import matplotlib.pyplot as plt # 计算逻辑回归给予X_test样本的决策数据值 # 通过decision_function可以调整精准率和召回率 decision_scores = log_reg.decision_function(X_test) fprs, tprs, thresholds = roc_curve(y_test, decision_scores) plt.plot(fprs, tprs) plt.show()

  ROC曲线距离左上角越近,证明分类器效果越好。如果一条算法1的ROC曲线完全包含算法2,则可以断定性能算法1>算法2。这很好理解,此时任做一条 横线(纵线),任意相同TPR(FPR) 时,算法1的FPR更低(TPR更高),故显然更优。

  很多时候两个分类器的ROC曲线交叉,无法判断哪个分类器性能更好,这时可以计算曲线下的面积AUC,作为性能度量。

AUC(曲线下面积):

  一般在ROC曲线中,我们关注是曲线下面的面积, 称为AUC(Area Under Curve)。这个AUC是横轴范围(0,1 ),纵轴是(0,1)所以总面积是小于1的。

ROC和AUC的主要应用:比较两个模型哪个好?主要通过AUC能够直观看出来。

ROC曲线下方由梯形组成,矩形可以看成特征的梯形。因此,AUC的面积可以这样算:(上底+下底)* 高 / 2,曲线下面的面积可以由多个梯形面积叠加得到。AUC越大,分类器分类效果越好。

AUC = 1,是完美分类器,采用这个预测模型时,不管设定什么阈值都能得出完美预测。绝大多数预测的场合,不存在完美分类器。

0.5 < AUC < 1,优于随机猜测。这个分类器(模型)妥善设定阈值的话,能有预测价值。

AUC = 0.5,跟随机猜测一样,模型没有预测价值。

AUC < 0.5,比随机猜测还差;但只要总是反预测而行,就优于随机猜测。

可以在sklearn中求出AUC值:

from sklearn.metrics import roc_auc_score print(roc_auc_score(y_test, decision_scores))

  【3】

[******代码基于波士顿房产预测的实际例子******]

import numpy as np import matplotlib.pyplot as plt from sklearn import datasets # 查看数据集描述 boston = datasets.load_boston() print(boston.DESCR) # 查看数据集的特征列表 print(boston.feature_names) # 取出数据中的第六例的所有行(房间数量) x = boston.data[:, 5] print(x.shape) # 取出样本标签 y = boston.target print(y.shape) plt.scatter(x, y) plt.show()

  

# 在图中我们可以看到 50W 美元的档分布着一些点 # 这些点可能是超出了限定范围 # 比如在问卷调查中,价格的最高档位是“50万及以上”,那么就全都划到50W上了,因此在本例中,可以将这部分数据去除 np.max(y) x = x[y < 50.0] y = y[y < 50.0] plt.scatter(x,y) plt.show()

  简单线性回归:

import numpy as np import matplotlib.pyplot as plt from sklearn import datasets # 查看数据集描述 boston = datasets.load_boston() # 取出数据中的第六例的所有行(房间数量) x = boston.data[:, 5] # 取出样本标签 y = boston.target # 在本例中,去除“50万及以上”的数据 np.max(y) x = x[y < 50.0] y = y[y < 50.0] from kNN_test.model_selection import train_test_split x_train, x_test, y_train, y_test = train_test_split(x, y, seed=666) print(x_train.shape) # (392,) print(y_train.shape) #(392,) print(x_test.shape) #(98,) print(y_test.shape) #(98,) from kNN_test.SimpleLinearRegression import SimpleLinearRegression reg = SimpleLinearRegression() reg.fit(x_train,y_train) print(reg.a_) # 7.8608543562689555 print(reg.b_) # -27.459342806705543 plt.scatter(x_train,y_train) plt.plot(x_train, reg.predict(x_train),color='r') plt.show() y_predict = reg.predict(x_test) print(y_predict)

  SimpleLinearRegression.py:

import numpy as np from .metrics import r2_score class SimpleLinearRegression: def __init__(self): """模型初始化函数""" self.a_ = None self.b_ = None def fit(self, x_train, y_train): """根据训练数据集x_train,y_train训练模型""" assert x_train.ndim ==1, \ "简单线性回归模型仅能够处理一维特征向量" assert len(x_train) == len(y_train), \ "特征向量的长度和标签的长度相同" x_mean = np.mean(x_train) y_mean = np.mean(y_train) num = (x_train - x_mean).dot(y_train - y_mean) # 分子 d = (x_train - x_mean).dot(x_train - x_mean) # 分母 self.a_ = num / d self.b_ = y_mean - self.a_ * x_mean return self def predict(self, x_predict): """给定待预测数据集x_predict,返回表示x_predict的结果向量""" assert x_predict.ndim == 1, \ "简单线性回归模型仅能够处理一维特征向量" assert self.a_ is not None and self.b_ is not None, \ "先训练之后才能预测" return np.array([self._predict(x) for x in x_predict]) def _predict(self, x_single): """给定单个待预测数据x_single,返回x_single的预测结果值""" return self.a_ * x_single + self.b_ def score(self, x_test, y_test): """根据测试数据x_test、y_test计算简单线性回归准确度(R方)""" y_predict = self.predict(x_test) return r2_score(y_test, y_predict) def __repr__(self): """返回一个可以用来表示对象的可打印字符串""" return "SimpleLinearRegression()"

    

 简单线性回归的目标是:已知训练数据样本x、y,找到a和b的值,使\sum_{i=1}^{m}\left (y^{(i)}-ax^{i}-b \right )^{2}尽可能小

实际上是找到训练数据集中\sum \left ( y_{train}^{(i)}-\widehat{y}_{train}^{(i)} \right )^{2}最小。

衡量标准是看在测试数据集中y的真实值与预测值之间的差距。

因此我们可以使用下面公式作为衡量标准:\sum \left ( y_{train}^{(i)}-\widehat{y}_{train}^{(i)} \right )^{2}

但是这里有一个问题,这个衡量标准是和m相关的。在具体衡量时,测试数据集不同将会导致误差的累积量不同。

首先我们从“使损失函数尽量小”这个思路出发:

对于训练数据集合来说,使\sum_{i=1}^{m}\left ( y_{train}^{(i)}-ax_{train}^{i}-b \right )^{2}尽可能小

在得到a和b之后将x_{test}代入a、b中。可以使用\sum_{i=1}^{m}\left ( y_{test}^{(i)}-\widehat{y}_{test}^{(i)} \right )^2来作为衡量回归算法好坏的标准。

MSE(均方误差):

  测试集中的数据量m不同,因为有累加操作,所以随着数据的增加 ,误差会逐渐积累;因此衡量标准和 m 相关。为了抵消掉数据量的形象,可以除去数据量,抵消误差。通过这种处理方式得到的结果叫做 均方误差MSE(Mean Squared Error):

                                                                         \frac{1}{m}\sum_{i=1}^{m}\left ( y_{test}^{(i)} -\widehat{y}_{test}^{(i)}\right )^2

  代码实现:

# MSE mse_test = np.sum((y_predict - y_test) ** 2) / len(y_test) print(mse_test)

RMSE(均方根误差):

  但是使用均方误差MSE收到量纲的影响。例如在衡量房产时,y的单位是(万元),那么衡量标准得到的结果是(万元平方)。为了解决量纲的问题,可以将其开方(为了解决方差的量纲问题,将其开方得到平方差)得到均方根误差RMSE(Root Mean Squarde Error):

                                                          \sqrt{\frac{1}{m}\sum_{i=1}^{m}\left ( y_{test}^{(i)} -\widehat{y}_{test}^{(i)}\right )^2}=\sqrt{MSE_{test}}

  代码实现:

# RMSE from math import sqrt rmse_test = sqrt(mse_test) print(rmse_test)

MAE(平均绝对误差):

  对于线性回归算法还有另外一种非常朴素评测标准。要求真实值y_{test}^{(i)}与 预测结果\widehat{y}_{test}^{(i)}之间的距离最小,可以直接相减做绝对值,加m次再除以m,即可求出平均距离,被称作平均绝对误差MAE(Mean Absolute Error):

            \frac{1}{m}\sum_{i=1}^{m}\left | y_{test}^{(i)} -\widehat{y}_{test}^{(i)} \right |

  在之前确定损失函数时,我们提过,绝对值函数不是处处可导的,因此没有使用绝对值。但是在评价模型时不影响。因此模型的评价方法可以和损失函数不同。

# MAE mae_test = np.sum(np.absolute(y_predict - y_test)) / len(y_test) print(mae_test)

R Squared:

  分类准确率,就是在01之间取值。但RMSE和MAE没有这样的性质,得到的误差。因此RMSE和MAE就有这样的局限性,比如我们在预测波士顿方差,RMSE值是4.9(万美元) 我们再去预测身高,可能得到的误差是10(厘米),我们不能说后者比前者更准确,因为二者的量纲根本就不是一类东西。

其实这种局限性,可以被解决。用一个新的指标R Squared:

  R^{2}=1-\frac{SS_{residual}}{SS_{total}}=1-\frac{\sum \left ( \widehat{y}^{(i)}-y^{(i)} \right )^2}{\sum \left ( \overline{y}-y^{(i)} \right )^2}

  

R方这个指标为什么好呢?

对于分子来说,预测值和真实值之差的平方和,即使用我们的模型预测产生的错误。

对于分母来说,是均值和真实值之差的平方和,即认为“预测值=样本均值”这个模型(Baseline Model)所产生的错误。

我们使用Baseline模型产生的错误较多,我们使用自己的模型错误较少。因此用1减去较少的错误除以较多的错误,实际上是衡量了我们的模型拟合住数据的地方,即没有产生错误的相应指标。

我们根据上述分析,可以得到如下结论:

R^2



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3