10. 机器学习-评测指标

news2025/7/19 4:15:14

茶桁的AI秘籍 10

Hi,你好。我是茶桁。

之前的课程中,我们学习了两个最重要的回归方法,一个线性回归,一个逻辑回归。也讲解了为什么学习机器学习要从逻辑回归和线性回归讲起。因为我们在解决问题的时候,有限选择简单的假设,越复杂的模型出错的概率也就越高。

本节课中,我们要继续我们未完成的内容。

还记得,咱们上一节课中最后所说的吗?在完成了基本回归之后,该如何去判断一个模型的好坏,以及如何调整和优化。

好,我们开始本节课程。

PICKLE

本节课中,会重点的给大家做一件事,叫「评测指标」。

在这之前,我们发现了一个麻烦事。就是我们现在需要去观测我们的分类结果,我们不得不再去执行一遍我们之前的训练程序,拿到最后的分类结果:

RM:6.38, LSTAT:24.08, EXPENSIVE:0, Predicated:0
...
RM:6.319, LSTAT:11.1, EXPENSIVE:1, Predicated:0

这很麻烦,训练结果每次要使用的时候都需要运行一次,这样非常的麻烦。现在我想要把这个model不要每一次都训练一下,而是要把它做一个保存,下次用的时候不需要从头到尾再训练一次。

现在现在,可以给他做一个persistence,做一个留存。现在就是要做这么一件事情。

import pickle

with open('logistic_regression.model', 'wb') as f:
    pickle.dump(model, f)

with open('w.model', 'wb') as f:
    pickle.dump(w, f)

with open('b.model', 'wb') as f:
    pickle.dump(b, f)

print('pickle finished')

---
pickle finished

并且最后我得到了三个文件,分别是logistic_regression.model, w.model以及b.model

在这里插入图片描述

现在就可以把训练完成的model做保存了。之后我们用Pytorch, tenserflow之类的做,它都有这样的功能。

到这一步之后,我们上一节上所写的代码就可以暂时不用了。不过为了整个代码的完整性,我仍然将其又在本节课的10.ipynb内些了一遍。

那么,我们要用的时候怎么办呢?如果要用这个对象的时候,将我们之前对文件操作的代码拿过来,然后将其中的wb参数改成rb,然后再将二进制文件读取一遍:

with open('logistic_regression.model', 'rb') as f:
    model_r = pickle.load(f)

with open('w.model', 'rb') as f:
    w_r = pickle.load(f)

with open('b.model', 'rb') as f:
    b_r = pickle.load(f)

print('pickle read finished')

rb的意思是read binary,也就是读取二进制文件。然后,为了在测试的时候避免混乱,让我接下来所使用的文件使用的是我重新读取的模型而不是之前训练时生成的的,我将重新读取的这几个文件命名为model_rw_r,b_r

那再之后,虽然不用重新训练了,但是数据还是要读取一遍的,并且,按照训练数据的规则重新整理好, 都完善了之后,就可以开搞进行分类了。

import pandas as pd
from sklearn.datasets import fetch_openml

dataset = fetch_openml(name='boston', version=1, as_frame=True, return_X_y=False, parser='pandas')

data = dataset['data']
target = dataset['target']

dataframe = pd.DataFrame(data)

rm = dataframe['RM']
lstat = dataframe['LSTAT']
dataframe['price'] = dataset['target']

greater_then_most = np.percentile(dataframe['price'], 66)
dataframe['expensive'] = dataframe['price'].apply(lambda p: int(p > greater_then_most))


expensive = dataframe['expensive']
random_test_indices = np.random.choice(range(len(rm)), size=100)
decision_boundary = 0.5

for i in random_test_indices:
    x1, x2, y = rm[i], lstat[i], expensive[i]
    predicate = model_r(np.array([x1, x2]), w_r, b_r)
    predicate_label = int(predicate > decision_boundary)

    print('RM:{}, LSTAT:{}, EXPENSIVE:{}, Predicated:{}'.format(x1, x2, y, predicate_label))

评测指标

好,解决了模型的重复使用之后,我们再回到课程中继续。

很多人在学习过程中,会觉得「评测指标」是一个没有那么有趣的事情。比方说,咱们学模型,学算法,就可以去写程序,可以运行,写出来的时候会感觉还蛮酷的。但是评测指标呢,很多同学就觉得不是那么有趣。

其实,我想告诉大家,评测指标是一个非常重要的东西。好比完成任何一个任务,不管你现在是完成普通的编程任务,还是要完成一个公司的市场行为、运营行为。一般来说,越复杂的任务,只要把评价指标,评价方式做对,这个任务基本上就已经完成了一半了。

对于我们来说,工作的时候要知道,对于一个机器学习任务,能找到正确的评测指标,这个机器学习任务就已经成功一半了。

首先,来看一个问题:Losses持续下降,到底是意味着什么呢?

import matplotlib.pyplot as plt
%matplotlib inline
plt.plot(losses)

在这里插入图片描述

loss持续下降意味着误差越来越小?方向是对的?测试值更加接近真实值?更精确的说法是,它在逼近最优解,但是效果是不是特别好,还不知道。

接下来这个问题是一个比较复杂的问题,是一个难点:

-np.sum(y * np.log(yhat) + (1 - y) * np.log(1 - yhat))

这段代码是我们写的loss函数, 我们现在来假设有一组数据:

true_label = np.array([1, 0, 1, 0, 1]) # 二分类

再假设有一个模型,在执行的时候,它会知道咱们做的是一个二分类问题,那么结果就是不是1,就是0。这个时候模型有可能偷懒,那给到的数据就会是随机的,好吧,开个玩笑,其实就只是因为数据不足造成给到的数据过于随机:

predicate_1 = np.array([0.8, 0.7, 0.8, 0.3, 0.8])

然后我们执行算法来拿到结果:

def test_lose(y, yhat):
    return -np.sum(y * np.log(yhat) + (1 - y) * np.log(1 - yhat))
test_lose(true_label, predicate_1)

---
2.2300784022072975

现在我们拿到的值为2.23,不过要记得,咱们这只是一个假设值。那这个时候引入我们刚才谈到的loss的曲线,loss是持续下降的,当它下降到最低的值的时候依然比这个2.23还要高,那就说明这个模型都还没有随机猜测的准确度高。

这个情况其实是经常会遇到的一个问题,你会看到你的的模型一直在下降,下降的非常好,但是一做实际测试的时候效果就特别差。

再换个说法就是,这个模型跑的时候,瞎猜的值都有2.23的准确,但是loss虽然一只在下降,一只下降到了3。虽然loss看起来在下降,但是这整个结果都不是太好。

瞎猜的时候的准确度,loss值,我们称为这个模型的Baseline。你的值最起码要比这个好。

所以就如之前所的,loss持续下降意味着模型在向着最优的方向在寻找,但并不意味着结果就会很好,因为有可能连瞎猜都不如。

好,以上是第一点,我们接着来看第二点。

loss一直在下降,但是我们现在想知道的是有多少个label预测对了。先建立两个变量来分别存储数据:

true_labels, predicated_labels = [], []

...
for i in random_test_indices:
    ...

    true_labels.append(y)
    predicated_labels.append(predicate_label)

然后分别获得了两组数据,一个是true_labels,一个是predicated_labels。有了这两组数据之后,我们来定义一个accuracy, 这个是预测的值和相似的值一共有多少个是一样的。

def accuracy(ytrues, ylabels):
    return sum(1 for yt, y1 in zip(ytrues, ylabels) if yt == y1) / len(ytrues)

accuracy(true_labels, precicated_labels)

---
0.89

0.89, 就是说有89%的label都是猜对了。

最早的时候其实只有这一个标记,但这个标记很容易出错。

假设有一个警察局,要在100个人里边判断谁是犯罪分子。现在我们知道有3个是犯罪分子,然后警察说这100个人全部都是犯罪分子。那么现在准确度有多少?

然后又有一个警察站出来说,这100个人都不是犯罪分子,那他的准确度又是多少?

我们现在让第一个警察是a,第二个警察是b。

警察b有97个标签都说对了,这会给人一种错觉,好像他预测的很准确的。但是其实,a和b两个人都判断的不准确。那我们这个时候就需要引出一个定义:Precision。

precision也是准确度的意思,和accuracy不同点是,accuracy的对比是对比目标和现有值是否匹配,匹配的就算正确。而precision除了看是否匹配之外,还要目标值,也就是positive。

这里举个例子说明一下,比如我们去检测是否有新冠病毒,那么目标是为了检测出有新馆病毒的人,那么呈阳性的人就是我们的positive, 那么我们precision除了预测出有新冠和没有新冠的人之外,有新冠的人也需要一一对应上,也就是positive要正确。

如果是写代码的话,也就是将之前的accuracy拿过来改改就可以直接用了:

def precision(ytrues, yhats):
    # 预测标签是1的里面,正确的比例是多少

    positives_pred = [y for y in yhats if y == 1]
    return sum(1 for yt, y in zip(ytrues, yhats) if yt == y and y == 1) / len(positives_pred)

precision(true_labels, predicated_labels)

---
0.8333333333333334

先将预测为1,也就是预测呈阳性的目标放到positives_pred中,再来检测一下在这些预测出来的目标中,预测对的有多少。

除此之外之外,还有一个值叫做recall,它的意思是在实际的positive里,有多少比例被找到了。

def recall(ytrues, yhats):
    
    true_positive = [y for y in ytrues if y == 1]     
    return sum(1 for yt, y in zip(ytrues, yhats) if yt == y and yt == 1) / len(true_positive)

recall(true_labels, predicated_labels)

---
0.8064516129032258

好,我们再来复盘一下这三个值,一个是accuracy, 一个是precision,一个是recall

accuracy就是预测值和实际值有多少是一样的。但是有可能会在实际场景都不是很均衡。

precision是拿到预测后的目标值,然后拿这些目标的实际值去比较看有多大比例是一样的。

recall是先拿到实际的目标值,然后拿目标预测值比较看有多大比例是一样的。

根据我们之前说的警察抓坏人的那个假设,我们现在来做一个测试,假设我们现在好人有90个,坏人有10个。

people = [0] * 90 + [1] * 10
import random
random.shuffle(people)

现在警察a来了,就判断说:全部都是好人,把他们全部都放了吧。这样的话,它的accuracy是多少呢?accuracy就是预测的,只要是实际值的那个label就行。我们来看看:

a = [0] * 100
accuracy(people, a)

---
0.9

我们看这个准确度就会很高,这个也能理解,因为警察a将这100个人中的90个好人全部判断准确了对吧?

让我们来看看其他两个:

precision(people, a)

---
ZeroDivisionError: division by zero

======
recall(people, a)

---
0

precision警告我们分母为0,报错了。那分母为什么为0呢?因为a说了,所有都是好人,那么预测的目标值,也就是分母上的坏人就为0。

而recall呢,结果为0。这是因为分母上的坏人实际值虽然为10,但是预测的目标值,也就是分子上为0。那结果肯定是为0。

本来a的accuracy是0.9,别人还以为准确度很高,结果一个坏人都没抓住。这肯定不行。

那b的情况又如何呢?之前说过,b说所有的都是坏人,统统抓起来。

b = [1] * 100
accuracy(people, b)

---
0.1

========
precision(people, b)

---
0.1

=========
recall(people, b)

---
1.0

虽然accuracyprecision都不高,但是似乎目标都被找出来了。颇有一种「宁可错杀1000,不可放过一个」的感觉。

那以上这些,就是为什么要有这3个非常重要的指标的原因。

好,那下一节课中,我们要来看看关于precitionrecall的一个矩阵,这个矩阵呢,将会是我们工作中分析结果常用的。

P r e c i s i o n = t p t p + f p R e c a l l = t p t p + f n \begin{align*} Precision & = \frac{tp}{ tp + fp} \\ Recall & = \frac{tp}{tp + fn} \end{align*} PrecisionRecall=tp+fptp=tp+fntp

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1104052.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

十七、文件(1)

本章概要 文件和目录路径 选取路径部分片段路径分析Paths 的增减修改 目录 在丑陋的 Java I/O 编程方式诞生多年以后,Java终于简化了文件读写的基本操作。 打开并读取文件对于大多数编程语言来说是非常常用的,由于 I/O 糟糕的设计以至于很少有人能够在不…

第七章 排序

第七章 排序 概述插入排序交换排序冒泡排序快速排序 选择排序直接选择排序堆排序 归并排序有序序列合并二路归并排序 小试牛刀 概述 排序就是将一组对象按照规定的次序(升序或降序等)重新排列的过程,往往为检索服务相同键值的两个记录在排序…

索引背后的数据结构——B+树

为什么要使用B树? 可以进行数据查询的数据结构有二叉搜索树、哈希表等。对于前者来说,树的高度越高,进行查询比较的时候访问磁盘的次数就越多。而后者只有在数据等于key值的时候才能进行查询,不能进行模糊匹配。所以出现了B树来解…

SQL数据库管理工具RazorSQL mac中文版特点与功能

RazorSQL mac是一款功能强大的SQL数据库管理工具,它支持多种数据库,包括MySQL、Oracle、Microsoft SQL Server、SQLite、PostgreSQL等。 RazorSQL mac 软件特点和功能 多种数据库支持:RazorSQL支持多种数据库,用户可以通过一个工…

故障预测与健康管理(PHM)在工业领域的发展前景

故障预测与健康管理(PHM)作为一种关键技术,已经在工业领域引起了广泛的关注和应用。PHM利用传感器、数据科学和智能算法等技术手段,通过实时监测和分析设备和系统的状态,提前发现潜在故障,并采取适当的维修…

制作linux系统内部yum源仓库

需求说明 制作内网linux系统yum源仓库,比较简单的方式就是添加系统镜像,此种yum配置方式可参考文章 https://blog.csdn.net/d1240673769/article/details/108477661 如果无法提供系统镜像,那该如何创建内网的yum源仓库呢?本文提…

互联网Java工程师面试题·Java 总结篇·第六弹

目录 56、TreeMap 和 TreeSet 在排序时如何比较元素?Collections 工具类中的 sort()方法如何比较元素? 57、Thread 类的 sleep()方法和对象的 wait()方法都可以让线程暂停执行,它们有什么区别? 58、线程的 sleep()方法和 yield()方法有什…

在nodejs中实现双重身份验证机制

在nodejs中实现双重身份验证机制 双重身份验证(Two-factor authentication)是一种安全机制,它要求用户提供两种不同的身份验证因素来访问他们的帐户:密码和发送到他们的移动设备的验证码。在本文中,我们将一步步通过使用speakeasy在nodejs中实…

deforum + kandinsky = 视频工作流

像搭积木一样玩AI,随着模型种类的不断丰富,不同的组合会带来什么惊喜?今天和大家分享最近看到的一个视频工作流(工具箱)。 首先,我们先对deforum和kandinsky做一些基本的介绍: deforum-art/defo…

【论文解读】单目3D目标检测 CUPNet(ICCV 2021)

本文分享单目3D目标检测,CUPNet 模型的论文解读,了解它的设计思路,论文核心观点,模型结构,以及效果和性能。 目录 一、CUPNet简介 二、论文核心观点 三、模型框架 四、损失函数 五、核心观点——3D高度估计误差 引…

Python之并发编程(进程)

文章目录 一、操作系统的发展史二、进程基础(操作系统中的概念)1.什么是进程2.进程的调度算法3.进程的并行与并发4.进程的三状态5.同步异步6.阻塞与非阻塞7.同步异步与阻塞非阻塞综合使用 三、如何创建进程Process的几个方法如何开启多进程进程间的数据默认隔离基于TCP协议的高…

【Qt控件之QButtonGroup】概述及使用

概述 QButtonGroup 类提供了一个容器来组织一组按钮部件。 QButtonGroup 提供了一个抽象容器,可以将按钮部件放置其中。它不提供此容器的可视表示(请参见 QGroupBox,用于容器部件),而是管理组中每个按钮的状态。 一个…

Electron webview 内网页 与 preload、 渲染进程、主进程的常规通信 以及企业级开发终极简化通信方式汇总

Electron 嵌入的页面中注入的是 preload.js 通过在标签中给 prelaod赋值,这里提到了 file://前缀,以及静态目录 static 怎么获取 实际代码,其中__static就是我们存放静态文件的地方,这个 static 是 electron 源代码根目录下的文件…

使用unordered_write调优RocksDB写性能

在使用rocksdb存储的服务中,我们发现QPS在4w/s就怎么调整都上不去了,写性能受到了某种限制。为什么呢?下图描述了rocksdb写入的流程。我们发现 unordered_write true可以提高写入吞吐量。 rocksdb的数据正常写入流程是,多个线程形…

九月 NFT 行业解读:熊市情绪仍占上风

作者: stellafootprint.network 9 月,著名主流媒体《滚石》(Rolling Stone)发表了一篇题为《你的 NFT 实际上——终于——完全不值钱了》(Your NFTs Are Actually — Finally — Totally Worthless)的文章&#xff0c…

【网络编程】从网络编程、TCP/IP开始到BIO、NIO入门知识(未完待续...)

目录 前言前置知识一、计算机网络体系结构二、TCP/IP协议族2.1 简介*2.2 TCP/IP网络传输中的数据2.3 地址和端口号2.4 小总结 三、TCP/UDP特性3.1 TCP特性TCP 3次握手TCP 4次挥手TCP头部结构体 3.2 UDP特性 四、总结 课程内容一、网络通信编程基础知识1.1 什么是Socket1.2 长连…

NumPy基础及取值操作

目录 第1关:ndarray对象 相关知识 怎样安装NumPy 什么是ndarray对象 如何实例化ndarray对象 使用array函数实例化ndarray对象 使用zeros,ones,empty函数实例化ndarray对象 代码文件 第2关:形状操作 相关知识 怎样改变n…

液压自动化成套设备比例阀放大器

液压电气成套设备的比例阀放大器是一种电子控制设备,用于控制液压动力系统中的液压比例阀1。 比例阀放大器通常采用电子信号进行控制,以控制比例阀的开度和流量,以实现液压系统的可靠控制。比例阀放大器主要由以下组成部分: 驱动…

tomcat 服务器

tomcat 服务器 tomcat: 是一个开源的web应用服务器。区别nginx,nginx主要处理静态页面,那么动态请求(连接数据库,动态页面)并不是nginx的长处,动态的请求会交给tomcat进行处理。 nginx-----转发动态请求-…

Golang学习:基础知识篇(三)—— Map(集合)

Golang学习:基础知识篇(三)—— Map集合 前言什么是Golang?Map集合定义 Map综合实例补充 前言 很久之前就想学Go语言了,但是一直有其他东西要学,因为我学的是Java嘛,所以后面学的东西一直是跟J…