【机器学习】(二)——如何评价模型的好坏

学习目标

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 <= test_ratio <= 1.0, \
        "test_train must be valid"

    if seed:
        # 是否使用随机种子,使随机结果相同,方便debug
        np.random.seed(seed)
        # permutation(n) 可直接生成一个随机排列的数组,含有n个元素
    shuffle_index = np.random.permutation(len(X))

    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]
    return X_train, X_test, y_train, y_test

调用(test.py)

from kNN_test.model_selection import train_test_split
from sklearn import datasets

iris = datasets.load_iris()

X = iris.data
y = iris.target

X_train, X_test, y_train, y_test = train_test_split(X, y)

print(X_train.shape)
print(X_test.shape)
print(y_train.shape)
print(y_test.shape)

sklearn中的train_test_split:

上面写的train_test_split也是在模仿sklearn的风格,我们可以直接在sklearn中调用:

from sklearn.model_selection import train_test_split
from sklearn import datasets

iris = datasets.load_iris()

X = iris.data
y = iris.target

X_train, X_test, y_train, y_test = train_test_split(X, y, 0.2, 666)

print(X_train.shape)
print(X_test.shape)
print(y_train.shape)
print(y_test.shape)

【2】

[********测评手写数字识别*******]

精准度

  在划分出测试数据集后,我们就可以验证其模型准确率了(accuracy)

  accuracy_score:函数计算分类准确率,返回被正确分类的样本比例(default)或者是数量(normalize=False)
  [在多标签分类问题中,该函数返回子集的准确率,对于一个给定的多标签样本,如果预测得到的标签集合与该样本真正的标签集合严格吻合,则subset accuracy =1.0否则是0.0]

from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier

X_train, X_test, y_train, y_test = train_test_split(X, y)
knn_clf = KNeighborsClassifier(n_neighbors=3)
knn_clf.fit(X_train, y_train)
y_predict = knn_clf.predict(X_test)

# 比对y_predict和y_test结果是否一致
print(sum(y_predict == y_test) / len(y_test))

  在我们自己的工程文件中添加一个metrics.py,用来度量性能的各种指标:

mport numpy as np
from math import sqrt

def accuracy_score(y_true, y_predict):
    """计算y_true和y_predict之间的准确率"""
    assert y_true.shape[0] != y_predict.shape[0], \
        "the size of y_true must be equal to the size of y_predict"
    return sum(y_true == y_predict) / len(y_true)

  调用:

from kNN_test.metrics import accuracy_score

accuracy_score(y_test, y_predict)

  更多的时候,我们还是使用sklearn中封装好的方法:

from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

X_train, X_test, y_train, y_test = train_test_split(X, y, 0.2,666)
knn_clf = KNeighborsClassifier(n_neighbors=3)
knn_clf.fit(X_train, y_train)
y_predict = knn_clf.predict(X_test)
print(accuracy_score(y_test, y_predict))

混淆矩阵

  {对于一个癌症预测系统,输入检查指标,判断是否患有癌症,预测准确度99.9%。这个系统是好是坏呢?

  如果癌症产生的概率是0.1%,那其实根本不需要任何机器学习算法,只要系统预测所有人都是健康的,即可达到99.9%的准确率。也就是说对于极度偏斜(Skewed Data)的数据,只使用分类准确度是不能衡量。}

  在此引入混淆矩阵(Confusion Matrix):

  对于二分类问题来说,所有的问题被分为0和1两类,混淆矩阵是2*2的矩阵:

 预测值0预测值1
真实值0TNFP
真实值1FNTP
  • TN:真实值是0,预测值也是0,即我们预测是negative,预测正确了。

  • FP:真实值是0,预测值是1,即我们预测是positive,但是预测错误了。

  • FN:真实值是1,预测值是0,即我们预测是negative,但预测错误了。

  • TP:真实值是1,预测值是1,即我们预测是positive,预测正确了。

  现在假设有1万人进行预测,填入混淆矩阵如下:

 预测值0预测值1
真实值0997812
真实值128

  对于1万个人中,有9978个人本身并没有癌症,我们的算法也判断他没有癌症;有12个人本身没有癌症,但是我们的算法却错误地预测他有癌症;有2个人确实有癌症,但我们算法预测他没有癌症;有8个人确实有癌症,而且我们也预测对了。

  因为混淆矩阵表达的信息比简单的分类准确度更全面,因此可以通过混淆矩阵得到一些有效的指标。

  代码实现:

import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

digits = datasets.load_digits()
X = digits.data
y = digits.target.copy()

# 要构造偏斜数据,将数字9的对应索引的元素设置为1,0~8设置为0
y[digits.target==9]=1
y[digits.target!=9]=0

# 使用逻辑回归做一个分类
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)

log_reg = LogisticRegression()
log_reg.fit(X_train,y_train)
# 得到X_test所对应的预测值
y_log_predict = log_reg.predict(X_test)

# 分类准确度
print(log_reg.score(X_test, y_test))

# 定义混淆指标:TN
def TN(y_true, y_predict):
    assert len(y_true) == len(y_predict)
    # (y_true == 0):向量与数值按位比较,得到的是一个布尔向量
    # 向量与向量按位与,结果还是布尔向量
    # np.sum 计算布尔向量中True的个数(True记为1,False记为0)
    return np.sum((y_true == 0) & (y_predict == 0))
    # 向量与向量按位与,结果还是向量

print(TN(y_test, y_log_predict))

# 定义混淆指标:FP
def FP(y_true, y_predict):
    assert len(y_true) == len(y_predict)
    # (y_true == 0):向量与数值按位比较,得到的是一个布尔向量
    # 向量与向量按位与,结果还是布尔向量
    # np.sum 计算布尔向量中True的个数(True记为1,False记为0)
    return np.sum((y_true == 0) & (y_predict == 1))  # 向量与向量按位与,结果还是向量

print(FP(y_test, y_log_predict))

# 定义混淆指标:FN
def FN(y_true, y_predict):
    assert len(y_true) == len(y_predict)
    # (y_true == 0):向量与数值按位比较,得到的是一个布尔向量
    # 向量与向量按位与,结果还是布尔向量
    # np.sum 计算布尔向量中True的个数(True记为1,False记为0)
    return np.sum((y_true == 1) & (y_predict == 0))  # 向量与向量按位与,结果还是向量

print(FN(y_test, y_log_predict))

# 定义混淆指标:TP
def TP(y_true, y_predict):
    assert len(y_true) == len(y_predict)
    # (y_true == 0):向量与数值按位比较,得到的是一个布尔向量
    # 向量与向量按位与,结果还是布尔向量
    # np.sum 计算布尔向量中True的个数(True记为1,False记为0)
    return np.sum((y_true == 1) & (y_predict == 1))  # 向量与向量按位与,结果还是向量

print(TP(y_test, y_log_predict))

# 输出混淆矩阵
def confusion_matrix(y_true, y_predict):
    return np.array([
        [TN(y_true, y_predict), FP(y_true, y_predict)],
        [FN(y_true, y_predict), TP(y_true, y_predict)]
    ])

print(confusion_matrix(y_test, y_log_predict))

精准率(查准率)

  因accuracy定义清洗、计算方法简单,因此经常被使用。但是它在某些情况下并不一定是评估模型的最佳工具。精度(查准率)和召回率(查全率)等指标对衡量机器学习的模型性能在某些场合下要比accuracy更好。

    根据混淆矩阵可以求得指标:

 预测值0预测值1
真实值09978(TN)12(FP)
真实值12(FN)8(TP)

  精准率:precision=\frac{TP}{TP+FP} ,即精准率为8/(8+12)=40%。所谓的精准率是:分母为所有预测为1的个数,分子是其中预测对了的个数,即预测值为1,且预测对了的比例。

  为什么管它叫精准率呢?在有偏的数据中,我们通常更关注值为1的特征,比如“患病”,比如“有风险”。在100次结果为患病的预测,平均有40次预测是对的。即:精准率为我们关注的那个事件,预测的有多准

  代码实现:

def precision_score(y_true, y_predict):
    tp = TP(y_true, y_predict)
    fp = FP(y_true, y_predict)
    try:
        return tp / (tp + fp)
    except:
        return 0.0
print(precision_score(y_test, y_log_predict))

召回率(查全率)

  召回率:recall=\frac{TP}{TP+FN}  ,即精准率为8/(8+2)=80%。所谓召回率是:所有真实值为1的数据中,预测对了的个数。每当有100个癌症患者,算法可以成功的预测出8个 。也就是我们关注的那个事件真实的发生情况下,我们成功预测的比例是多少

  那么为什么需要精准率和召回率呢?还是下面的这个例子,有10000个人,混淆矩阵如下:

 预测值0预测值1
真实值0997812
真实值128

  如果我们粗暴的认为所有人都是健康的,那算法的准确率是99.78%,但这是毫无意义的。如果算精准率则是40%,召回率是80%。

  有的时候,对于一个算法而言,精准率高一些,召回率低一些;或者召回率高一些,精准率低一些。该如何取舍呢?

    【答:视场景而定】

  比如我们做了一个股票预测系统,未来股票是📈还是📉这样一个二分类问题。很显然“涨”才是我们关注的焦点,那么我们肯定希望:系统预测上涨的股票中,真正上涨的比例越大越好,这就是希望查准率高。那么我们是否关注查全率呢?在大盘中有太多的真实上涨股票,虽然我们漏掉了一些上升周期,但是我们没有买进,也就没有损失。但是如果查准率不高,预测上涨的结果下跌了,那就是实实在在的亏钱了。所以在这个场景中,查准率更重要。

  当然也有追求召回率的场景,在医疗领域做疾病诊断,如果召回率低,意味着本来有一个病人得病了,但是没有正确预测出来,病情就恶化了。我们希望尽可能地将所有有病的患者都预测出来,而不是在看在预测有病的样例中有多准。

  代码实现:

def recall_score(y_true, y_predict):
    tp = TP(y_true, y_predict)
    fn = FN(y_true, y_predict)
    try:
        return tp / (tp + fn)
    except:
        return 0.0
print(recall_score(y_test, y_log_predict))

scikit-learn中的混淆矩阵,精准率和召回率:

from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

digits = datasets.load_digits()
X = digits.data
y = digits.target.copy()

# 要构造偏斜数据,将数字9的对应索引的元素设置为1,0~8设置为0
y[digits.target==9]=1
y[digits.target!=9]=0

# 使用逻辑回归做一个分类
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)

log_reg = LogisticRegression()
log_reg.fit(X_train,y_train)
# 得到X_test所对应的预测值
y_log_predict = log_reg.predict(X_test)

# 混淆矩阵
from sklearn.metrics import confusion_matrix

print(confusion_matrix(y_test, y_log_predict))
# 输出:
# array([[403,   2],
#       [  9,  36]])

# 精准率
from sklearn.metrics import precision_score

print(precision_score(y_test, y_log_predict))
# 输出:
# 0.947368421053

# 召回率
from sklearn.metrics import recall_score

print(recall_score(y_test, y_log_predict))
# 输出:
# 0.8

  但是,在实际业务场景中,也有很多没有这么明显的选择。那么在同时需要关注精准率和召回率,如何在两个指标中取得平衡呢?在这种情况下,我们使用一种新的指标:F1 Score

F1 Score(二者兼顾)

  如果要我们综合精准率和召回率这两个指标,我们可能会想到取平均值这样的方法。F1 Score的思想也差不多:

  F1 Score 是精准率和召回率的调和平均值:F1=\frac{2\cdot precision\cdot recall}{precision+recall}

  什么是调和平均值?为什么要取调和平均值?调和平均值的特点是如果二者极度不平衡,如某一个值特别高、另一个值特别低时,得到的F1 Score值也特别低;只有二者都非常高,F1才会高。这样才符合我们对精准率和召回率的衡量标准。

                                                             \frac{1}{F1}=\frac{1}{2}\left ( \frac{1}{precision}+\frac{1}{recall} \right )

  代码实现:

def f1_score(precision, recall):
    try:
        return 2 * precision * recall / (precision + recall)
    except:
        return 0.0

print(f1_score(precision_score(y_test, y_log_predict),recall_score(y_test, y_log_predict)))

ROC曲线

  基础概念:

  1、分类阈值,即设置判断样本为正例的阈值thr,

  如果某个逻辑回归模型对某封电子邮件进行预测时返回的概率为 0.9995,则表示该模型预测这封邮件非常可能是垃圾邮件。相反,在同一个逻辑回归模型中预测分数为 0.0003 的另一封电子邮件很可能不是垃圾邮件。可如果某封电子邮件的预测分数为 0.6 呢?为了将逻辑回归值映射到二元类别,您必须指定分类阈值(也称为判定阈值)。如果值高于该阈值,则表示“垃圾邮件”;如果值低于该阈值,则表示“非垃圾邮件”。人们往往会认为分类阈值应始终为 0.5,但阈值取决于具体问题,因此您必须对其进行调整。

  2、TPR:预测为1,且预测对了的数量,占真实值为1的数据百分比。很好理解,就是召回率。 

                                                             TPR=recall=\frac{TP}{TP+FN}

  3、FPR:预测为1,但预测错了的数量,占真实值不为1的数据百分比。与TPR相对应,FPR除以真实值为0的这一行所有的数字和 FPR=\frac{FP}{TN+FP}

TPR和FPR之间是成正比的,TPR高,FPR也高。ROC曲线就是刻画这两个指标之间的关系。

[ROC曲线]:

ROC曲线(Receiver Operation Characteristic Cureve),描述TPR和FPR之间的关系。x轴是FPR,y轴是TPR。

我们已经知道,TPR就是所有正例中,有多少被正确地判定为正;FPR是所有负例中,有多少被错误地判定为正 分类阈值取不同值,TPR和FPR的计算结果也不同,最理想情况下,我们希望所有正例 & 负例 都被成功预测  TPR=1,FPR=0,即 所有的正例预测值 > 所有的负例预测值,此时阈值取最小正例预测值与最大负例预测值之间的值即可。

TPR越大越好,FPR越小越好,但这两个指标通常是矛盾的。为了增大TPR,可以预测更多的样本为正例,与此同时也增加了更多负例被误判为正例的情况。

代码实现:

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

digits = datasets.load_digits()
X = digits.data
y = digits.target.copy()

# 要构造偏斜数据,将数字9的对应索引的元素设置为1,0~8设置为0
y[digits.target == 9] = 1
y[digits.target != 9] = 0

# 使用逻辑回归做一个分类
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)

log_reg = LogisticRegression()
log_reg.fit(X_train, y_train)
# 计算逻辑回归给予X_test样本的决策数据值
# 通过decision_function可以调整精准率和召回率
decision_scores = log_reg.decision_function(X_test)

def TN(y_true, y_predict):
    assert len(y_true) == len(y_predict)
    # (y_true == 0):向量与数值按位比较,得到的是一个布尔向量
    # 向量与向量按位与,结果还是布尔向量
    # np.sum 计算布尔向量中True的个数(True记为1,False记为0)
    return np.sum((y_true == 0) & (y_predict == 0))
    # 向量与向量按位与,结果还是向量


# 定义混淆指标:FP
def FP(y_true, y_predict):
    assert len(y_true) == len(y_predict)
    # (y_true == 0):向量与数值按位比较,得到的是一个布尔向量
    # 向量与向量按位与,结果还是布尔向量
    # np.sum 计算布尔向量中True的个数(True记为1,False记为0)
    return np.sum((y_true == 0) & (y_predict == 1))  # 向量与向量按位与,结果还是向量

# 定义混淆指标:FN
def FN(y_true, y_predict):
    assert len(y_true) == len(y_predict)
    # (y_true == 0):向量与数值按位比较,得到的是一个布尔向量
    # 向量与向量按位与,结果还是布尔向量
    # np.sum 计算布尔向量中True的个数(True记为1,False记为0)
    return np.sum((y_true == 1) & (y_predict == 0))  # 向量与向量按位与,结果还是向量

# 定义混淆指标:TP
def TP(y_true, y_predict):
    assert len(y_true) == len(y_predict)
    # (y_true == 0):向量与数值按位比较,得到的是一个布尔向量
    # 向量与向量按位与,结果还是布尔向量
    # np.sum 计算布尔向量中True的个数(True记为1,False记为0)
    return np.sum((y_true == 1) & (y_predict == 1))  # 向量与向量按位与,结果还是向量


# TPR
def TPR(y_true, y_predict):
    tp = TP(y_true, y_predict)
    fn = FN(y_true, y_predict)
    try:
        return tp / (tp + fn)
    except:
        return 0.0


# FPR
def FPR(y_true, y_predict):
    fp = FP(y_true, y_predict)
    tn = TN(y_true, y_predict)
    try:
        return fp / (fp + tn)
    except:
        return 0.0


fprs = []
tprs = []

# 以0.1为步长,遍历decision_scores中的最小值到最大值的所有数据点,将其作为阈值集合
thresholds = np.arange(np.min(decision_scores), np.max(decision_scores), 0.1)
for threshold in thresholds:
    # decision_scores >= 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 <= 1

  • R2越大也好,越大说明减数的分子小,错误率低;当我们预测模型不犯任何错误时,R2最大值1

  • 当我们的模型等于基准模型时,R^2 = 0

  • 如果R^2 < 0,说明我们学习到的模型还不如基准模型。此时,很有可能我们的数据不存在任何线性关系。

  • 11
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
深度学习(DL,Deep Learning)是机器学习(ML,Machine Learning)领域中一个新的研究方向,它被引入机器学习使其更接近于最初的目标——人工智能(AI,Artificial Intelligence)。 [1] 深度学习是学习样本数据的内在规律和表示层次,这些学习过程中获得的信息对诸如文字、图像和声音等数据的解释有很大的帮助。它的最终目标是让机器能够像人一样具有分析学习能力,能够识别文字、图像和声音等数据。 深度学习是一个复杂的机器学习算法,在语音和图像识别方面取得的效果,远远超过先前相关技术。 [1] 深度学习在搜索技术、数据挖掘、机器学习、机器翻译、自然语言处理、多媒体学习、语音、推荐和个性化技术,以及其他相关领域都取得了很多成果。深度学习使机器模仿视听和思考等人类的活动,解决了很多复杂的模式识别难题,使得人工智能相关技术取得了很大进步。 [1] 深度学习是一类模式分析方法的统称,就具体研究内容而言,主要涉及三类方法: [2] (1)基于卷积运算的神经网络系统,即卷积神经网络(CNN)。 [2] (2)基于多层神经元的自编码神经网络,包括自编码(Auto encoder)以及近年来受到广泛关注的稀疏编码两类(Sparse Coding)。 [2] (3)以多层自编码神经网络的方式进行预训练,进而结合鉴别信息进一步优化神经网络权值的深度置信网络(DBN)。 [2] 通过多层处理,逐渐将初始的“低层”特征表示转化为“高层”特征表示后,用“简单模型”即可完成复杂的分类等学习任务。由此可将深度学习理解为进行“特征学习”(feature learning)或“表示学习”(representation learning)。 [3] 以往在机器学习用于现实任务时,描述样本的特征通常需由人类专家来设计,这成为“特征工程”(feature engineering)。众所周知,特征的好坏对泛化性能有至关重要的影响,人类专家设计出好特征也并非易事;特征学习(表征学习)则通过机器学习技术自身来产生好特征,这使机器学习向“全自动数据分析”又前进了一步。 [3] 近年来,研究人员也逐渐将这几类方法结合起来,如对原本是以有监督学习为基础的卷积神经网络结合自编码神经网络进行无监督的预训练,进而利用鉴别信息微调网络参数形成的卷积深度置信网络。与传统的学习方法相比,深度学习方法预设了更多的模型参数,因此模型训练难度更大,根据统计学习的一般规律知道,模型参数越多,需要参与训练的数据量也越大。 [2] 20世纪八九十年代由于计算机计算能力有限和相关技术的限制,可用于分析的数据量太小,深度学习在模式分析中并没有表现出优异的识别性能。自从2006年,Hinton等提出快速计算受限玻耳兹曼机(RBM)网络权值及偏差的CD-K算法以后,RBM就成了增加神经网络深度的有力工具,导致后面使用广泛的DBN(由Hin
matlab常用代码大全,帮助你科研,论文实证分析,数模竞赛 第44章 层次分析法 第45章 灰色关联度 第46章 熵权法 第47章 主成分分析 第48章 主成分回归 第49章 偏最小二乘 第50章 逐步回归分析 第51章 模拟退火 第52章 RBF,GRNN,PNN-神经网络 第53章 竞争神经网络与SOM神经网络 第54章 蚁群算法tsp求解 第55章 灰色预测GM1-1 第56章 模糊综合评价 第57章 交叉验证神经网络 第58章 多项式拟合 plotfit 第59章 非线性拟合 lsqcurefit 第60章 kmeans聚类 第61章 FCM聚类 第62章 arima时间序列 第63章 topsis 第1章 BP神经网络的数据分类——语音特征信号分类 第2章 BP神经网络的非线性系统建模——非线性函数拟合 第3章 遗传算法优化BP神经网络——非线性函数拟合 第4章 神经网络遗传算法函数极值寻优——非线性函数极值寻优 第5章 基于BP_Adaboost的强分类器设计——公司财务预警建模 第6章 PID神经元网络解耦控制算法——多变量系统控制 第7章 RBF网络的回归--非线性函数回归的实现 第8章 GRNN网络的预测----基于广义回归神经网络的货运量预测 第9章 离散Hopfield神经网络的联想记忆——数字识别 第10章 离散Hopfield神经网络的分类——高校科研能力评价 第11章 连续Hopfield神经网络的优化——旅行商问题优化计算 第12章 初始SVM分类与回归 第13章 LIBSVM参数实例详解 第14章 基于SVM的数据分类预测——意大利葡萄酒种类识别 第15章 SVM的参数优化——如何更好的提升分类器的性能 第16章 基于SVM的回归预测分析——上证指数开盘指数预测. 第17章 基于SVM的信息粒化时序回归预测——上证指数开盘指数变化趋势和变化空间预测 第18章 基于SVM的图像分割-真彩色图像分割 第19章 基于SVM的手写字体识别 第20章 LIBSVM-FarutoUltimate工具箱及GUI版本介绍与使用 第21章 自组织竞争网络在模式分类中的应用—患者癌症发病预测 第22章 SOM神经网络的数据分类--柴油机故障诊断 第23章 Elman神经网络的数据预测----电力负荷预测模型研究 第24章 概率神经网络的分类预测--基于PNN的变压器故障诊断 第25章 基于MIV的神经网络变量筛选----基于BP神经网络的变量筛选 第26章 LVQ神经网络的分类——乳腺肿瘤诊断 第27章 LVQ神经网络的预测——人脸朝向识别 第28章 决策树分类器的应用研究——乳腺癌诊断 第29章 极限学习机在回归拟合及分类问题中的应用研究——对比实验 第30章 基于随机森林思想的组合分类器设计——乳腺癌诊断 第31章 思维进化算法优化BP神经网络——非线性函数拟合 第32章 小波神经网络的时间序列预测——短时交通流量预测 第33章 模糊神经网络的预测算法——嘉陵江水质评价 第34章 广义神经网络的聚类算法——网络入侵聚类 第35章 粒子群优化算法的寻优算法——非线性函数极值寻优 第36章 遗传算法优化计算——建模自变量降维 第37章 基于灰色神经网络的预测算法研究——订单需求预测 第38章 基于Kohonen网络的聚类算法——网络入侵聚类 第39章 神经网络GUI的实现——基于GUI的神经网络拟合、模式识别、聚类 第40章 动态神经网络时间序列预测研究——基于MATLAB的NARX实现 第41章 定制神经网络的实现——神经网络的个性化建模与仿真 第42章 并行运算与神经网络——基于CPU/GPU的并行神经网络运算 第43章 神经网络高效编程技巧——基于MATLAB R2012b新版本特性的探讨

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值