周志华《机器学习》习题3.4——用UCI数据集比较10折交叉验证法和留一法
1.题目
选择两个 UCI 数据集,比较 10 折交叉验证法和留一法所估计出的对率回归的错误率。(本文就对一个UCI数据集用两种评估方法实现了,毕竟再对另一个数据集的实现方法是一样的)
2.下载UCI数据集
导入数据集的方法有很多,可以直接从官网下载数据集文件,也从keras库里直接导入,本文使用第一种方法。
首先,进入UCI官网:https://archive.ics.uci.edu/ml/
在UCI主页下的 Most Popular Data Sets 能看见由很多常用数据集,包含最常用的鸢(yuan)尾花、酒、车等等,本文就使用最经典的鸢尾花了。
点击IRIS图标进入鸢尾花数据集页面:
这里表格包含了一些比较重要的信息:
同时,下方包含了对属性和类别的说明。
像该数据集,用于分类任务,包含150条数据,每条数据含有4个属性,不存在数据缺失,拥有3个类别(也就是多分类任务)。
确认数据集是我们想要的后,点击Data Folder进入数据的文件目录。
然后,点击iris.data下载该数据集文件。
打开下载后的文件,可以看到,每条数据(对应每朵花)占一行,每行包含用逗号隔开的4个数字和1个字符串,每个数字对应一朵花的对应属性值,字符串表示该条数据属于的类别。
3.实现思路
3.1 评估方法
本题需要实现两种评估算法,分别为10折交叉验证和留一法。
首先,对于10折交叉验证,其思想是将数据集划分为10份(划几份就是几折),然后任取1份做测试集,另取9份做训练集,根据排列组合可知有10种取法,然后,对于每种取法,对学习器(本文使用对率回归模型)进行训练,然后用测试集测试,10轮后能得到10个正确率(注意每轮训练都是重新训练,也就是说,一共要训练和测试10次),最后将10个正确率取平均值当作最后该模型的正确率。
然后,对于留一法,简单来说就是m折交叉认证(m等于数据实例数),对于该数据集就是150折交叉验证,每轮留1个做测试集,其余149个做训练集,最后会得到150个准确率(当然,不是100%就是0%),然后取平均值作为模型正确率。
3.2 多分类方法
对于线性模型,多分类任务一般使用拆分策略,即将任务差分为多个二分类任务,拆分策略包括一对一(OvO)、一对多(OvR)和多对多(MvM)。本文将会使用OvR实现多分类。
这里讲一下OvO,该策略会将任务中的多个类别两两组合,然后对于每个组合,将其看作一个二分类任务(例如本题有3个类,有3种组合方法,需要训练三个二分类学习器),训练完成后,在预测时,只需要将测试实例输入到这些二分类学习器中,最后统计哪个类别结果多即可。
OvR则是将任务中的多个类别按照“一个类是正类,其余类都是负类”的规则划分,例如本例中包含三个花的类别:Iris-setosa、Iris-versicolor、Iris-virginica,先将Iris-setosa视为正例,然后将Iris-versicolor、Iris-virginica视为反例,这样就会形成一个二分类学习器,然后同理能一共得到三个二分类学习器,在预测时,只需要将测试实例分别输入到三个学习器中,观察三个学习器的结果,然后看哪个学习器输出正例,则认为该实例属于对应类别。而对于MvM,由于这里只有3个类别,使用MvM也会退化成OvR,所以无需使用了。
4. python实现
(1)读取数据集
将数据集文件按照行依次读取,每行按逗号分割,然后将用于表示类别的字符串转换为数字(三个类对应数字1,2,3)。
import numpy as np
import math
import random# 读取UCI数据集
def read_uci(dir):iris = []with open(dir, 'r+') as f:for line in f.readlines():iris.append(line.split(','))x = []y = []for iri in iris[:-1]:name = iri[4]x.append([float(xi) for xi in iri[:-1]])if "setosa" in name:y.append(1)elif "versicolor" in name:y.append(2)elif "virginica" in name:y.append(3)return x,y
(2) 二分类实现
实现多分类学习器前,先要实现二分类学习器,本文使用对率回归模型,对对率回归的损失函数进行梯度下降,其中对率回归的损失函数为:
l(β)=∑i=1m[−yiβTx^i+ln(eβTx^i+1)]\boldsymbol{l{}}(\boldsymbol{\beta}) = \sum_{i=1}^{m}[-y_{i}\beta^{T}\widehat{x}_{i}+\ln(e^{\beta^{T}\widehat{x}_{i}}+1)]l(β)=i=1∑m[−yiβTxi+ln(eβTxi+1)]
梯度下降公式为:
βt+1=βt−s∂l(β)∂β\boldsymbol{\beta} ^{t+1}=\boldsymbol{\beta} ^{t}-s\frac{\partial \boldsymbol{l{}}(\boldsymbol{\beta})}{\partial \boldsymbol{\beta}} βt+1=βt−s∂β∂l(β)
按照上述公式实现梯度下降即可。然后说一下超参数,这里对beta设置初始值为全1,d表示收敛的界限,就是当beta在下降过程中如果不超过0.01则表示已经收敛,就不用继续下降了,alpha表示步长(对应公式的s),n表示最大下降次数。这些值设置可以相对随意,然后经过测试可以找到一个比较好的参数,本文就测试了6、7次,按照最高正确率选出的参数。
def train_2(x:np.array, y:np.array):beta = np.array([1.0,1.0,1.0,1.0,1.0]).Td = 0.01 # 变化量小于d时表示收敛alpha = 0.005n = 500 for i in range(n):dl_sum = 0for i in range(np.shape(x)[0]):xi_hat = np.r_[x[i], 1].Tei = np.math.exp(beta.T.dot(xi_hat))p1 = ei / (1 + ei)dl = xi_hat.dot(y[i]-p1)dl_sum -= dl
# print(dl_sum)if np.all(dl_sum < d) and np.all(dl_sum > -d):breakbeta -= alpha * dl_sum;return beta
(3)三分类学习器
二分类实现完,就可以实现三分类了,主要就是把y,也就是标签处理一下,这里第一个循环用于将1类看为正类,2、3类分为反类,以此类推,第二个循环是,2正,1、3反,第三个循环是,3正,1,2反。
def train_3(x, y):y1 = []for yi in y:if yi == 1:y1.append(1)else:y1.append(0)beta1 = train_2(x, y1)print("学习器1训练完成,参数:", beta1)y2 = []for yi in y:if yi == 2:y2.append(1)else:y2.append(0)beta2 = train_2(x, y2)print("学习器2训练完成,参数:", beta2)y3 = []for yi in y:if yi == 3:y3.append(1)else:y3.append(0)beta3 = train_2(x, y3)print("学习器3训练完成,参数:", beta3)return beta1, beta2, beta3
(4)10折交叉验证
这里为了实现每折数据的类别比例都是1:1:1,将数据集先按照类别分开,然后在各自打乱,最后再分成10部分,取9部分训练1部分测试。
def cv10_devide_test(x, y):sumn = len(x)r_rate_sum = 0x1 = []x2 = []x3 = []for i in range(sumn):if y[i] == 1:x1.append(x[i])elif y[i] == 2:x2.append(x[i])elif y[i] == 3:x3.append(x[i])random.shuffle(x1)random.shuffle(x2)random.shuffle(x3)for i in range(10):train_x = []train_y = []test_x = []test_y = []x1_delta = len(x1)/10x2_delta = len(x2)/10x3_delta = len(x3)/10for j in range(len(x1)):if j >= i*x1_delta and j < (i+1)*x1_delta:test_x.append(x1[j])test_y.append(1)else:train_x.append(x1[j])train_y.append(1)for j in range(len(x2)):if j >= i*x2_delta and j < (i+1)*x2_delta:test_x.append(x2[j])test_y.append(2)else:train_x.append(x2[j])train_y.append(2)for j in range(len(x3)):if j >= i*x3_delta and j < (i+1)*x3_delta:test_x.append(x3[j])test_y.append(3)else:train_x.append(x3[j])train_y.append(3)# print("train_x:", train_x)
# print("train_y:", train_y)
# print("test_x:", test_x)
# print("test_y:", test_y)beta1, beta2, beta3 = train_3(train_x, train_y)print(f"第{i+1}折训练完成")r_rate = test(beta1, beta2, beta3, test_x, test_y)r_rate_sum += r_rateavg_r_rate = r_rate_sum/10print("交叉验证平均正确率为:",avg_r_rate)return train_x, train_y, test_x, test_y
(5)留一法
留一法与上面交叉验证一样,区别在于只留一个进行测试,所以要进行150次训练测试,运行时间会长一些。
def cv1_devide_test(x, y):sumn = len(x)r_rate_sum = 0for i in range(sumn):train_x = []train_y = []test_x = []test_y = []for j in range(sumn):if j == i:test_x.append(x[j])test_y.append(y[j])else:train_x.append(x[j])train_y.append(y[j])beta1, beta2, beta3 = train_3(train_x, train_y)r_rate = test(beta1, beta2, beta3, test_x, test_y)r_rate_sum += r_rateprint(f"第{i+1}折训练完成")avg_r_rate = r_rate_sum/sumnprint("留一法平均正确率为:",avg_r_rate)return train_x, train_y, test_x, test_y
(6)其他函数
# sigmoid函数
def sigmoid(x):if x<-500:x = -500return 1 / (1 + math.exp(-x))# 判断两个浮点是是否相同
def float_equal(a, b):delta = a-bif delta > -1e-5 and delta < 1e-5:return Trueelse:return False# 预测
def predict(beta, x):y = 0for i in range(len(x)):y += x[i] * beta[i]y += beta[len(x)]return sigmoid(y)# 测试
def test(beta1, beta2, beta3, test_x, test_y):right = 0for i in range(len(test_x)):y1 = predict(beta1, test_x[i])y2 = predict(beta2, test_x[i])y3 = predict(beta3, test_x[i])if y1 >= 0.5 and test_y[i] == 1:right += 1elif y2 >= 0.5 and test_y[i] == 2:right += 1elif y3 >= 0.5 and test_y[i] == 3:right += 1r_rate = right/len(test_x)print("测试样例总数:", len(test_x))print("通过样例数:", right)print("正确率为:", r_rate)return r_rate
(7)主程序
if __name__ == "__main__":x,y = read_uci("./iris.data")cv10_devide_test(x, y)cv1_devide_test(x, y)
7. 结果
10折交叉验证结果:
留一法运行结果:
10折交叉验证准确率是86%,留一法是84%,但不代表交叉验证要好,因为在测试运行过程中,该程序的准确率是有浮动的,比如说前几次交叉验证会经常出现81%左右的结果,由于留一法需要运行时间比较长,我就只运行了一次。
所以如果要想得到严谨的比较结果,就可以多运行几个结果,然后再进行比较。
周志华《机器学习》习题3.4——用UCI数据集比较10折交叉验证法和留一法相关推荐
- 周志华西瓜书3.4题——用十折交叉验证法和留一法估计对率回归的误差
周志华西瓜书3.4题. 本文所编写的代码均使用python3.7进行调试,依靠的sklearn进行的实验. 第一步,导入iris数据集,数据集使用sklearn包里面自带的. from sklearn ...
- 周志华《机器学习》课后习题3.410折交叉验证法和留一法UCI实例比较
3.4选择两个UCI数据集,比较10折交叉验证法和留一法所估计出的对率回归的错误率. 利用SciKitLearn做十折交叉验证和留一法筛选 本文选用UCI提供的鸢尾花数据集和红酒产地数据集. Iris ...
- 《机器学习》课后习题 3.4 选择两个 UCI 数据集,比较 10 折交叉验证法和留 法所估计出的对率回归的错误率.
参考了han同学的答案,数据集也可在han同学的github上下载. 3.4 选择两个 UCI 数据集,比较 10 折交叉验证法和留 法所估计出的对率回归的错误率. import numpy as n ...
- 机器学习(MACHINE LEARNING)交叉验证(简单交叉验证、k折交叉验证、留一法)
文章目录 1 简单的交叉验证 2 k折交叉验证 k-fold cross validation 3 留一法 leave-one-out cross validation 针对经验风险最小化算法的过拟合 ...
- 《机器学习》周志华课后习题答案——第三章 (1-7题)
<机器学习>周志华课后习题答案--第三章 (1-7题) 文章目录 <机器学习>周志华课后习题答案--第三章 (1-7题) 一.试析在什么情形下式(3.2)中不必考虑偏置项b. ...
- 周志华机器学习课后习题解析【第二章】
作者 | 我是韩小琦 链接 | https://zhuanlan.zhihu.com/p/42435889 2.1 数据集包含 1000 个样本,其中 500 个正例. 500 个反例,将其划分为包含 ...
- 机器学习-周志华-课后习题答案-线性模型
3.1试分析在什么情况下,在以下式子中不比考虑偏置项b. 答:在线性回归中,所有参数的确定都是为了让残差项的均值为0且残差项的平方和最小.在所有其他参数项确定后,偏置项b(或者说是常数项)的变化体现出 ...
- 【吃瓜教程】周志华机器学习西瓜书第三章答案
线性模型结构梳理 3.1 试析在什么情形下式3.2中不必考虑偏置项b 答案一: 偏置项b在数值上代表了自变量取0时,因变量的取值: 1.当讨论变量x对结果y的影响,不用考虑b: 2.可以用变量归一化( ...
- 周志华-机器学习西瓜书-第三章习题3.3 编程实现对率回归
本文为周志华机器学习西瓜书第三章课后习题3.3答案,编程实现对率回归,数据集为书本第89页的数据 使用tensorflow实现过程 # coding=utf-8 import tensorflow a ...
- 《机器学习》周志华课后习题答案——第一章(1-3题完结)
<机器学习>周志华课后习题答案--第一章 文章目录 <机器学习>周志华课后习题答案--第一章 一.表1.1中若只包含编号为1和4的两个样例,试给出相应的版本空间 二.与使用单个 ...
最新文章
- C#中父子窗口之间实现控件互操作
- abaqus生成adams柔性体_专栏 | HyperMesh_To_Abaqus接口——模型导入导出问题
- 2017.9.23 Count on a tree 思考记录
- 华为路由器ospf路由表解读_网络-路由交换-路由基础-华为-OSPF的工作原理
- POJ - 3461 (kmp)
- [PyTorch] 基于Python和PyTorch的线性拟合
- Harmony OS — PageSliderIndicator滑动页面指示器
- 【分享】React函数式组件写法优劣
- sprintf与swprintf
- Oracle RMAN 备份与恢复
- 444 nginx_nginx发布静态资源
- Android 私有权限白名单
- 编写函数求整形数组a中存储的m个不重复的整数的第k大的整数(其中m=1,1=k=m)很简单的一个思路是酱紫的:管他辣么多干啥,上来一把排序然后直接得答案...
- 服务器协议 重发 回包 039,3情报板预置播放表、位图一览表.doc
- 通过Safari浏览器获取iOS设备UDID(设备唯一标识符)
- 天玑9000和苹果a15哪个好
- 把kali linux 装进 U盘并实现数据可存储
- 数据挖掘之人工神经网络
- 快速调整 图片的 像素大小
- Linux极简快速入门|Linux操作系统(四)
热门文章
- 大数据入门介绍和学习路线
- 正交匹配追踪算法OMP
- smtp邮件服务器配置,配置SMTP服务器
- Java实现网上书店管理系统(idea+MySQL+navicat)
- 服务器“**”上的MSDTC不可用的解决办法
- 设计师案头必备的配色灵感宝典软件\插件!
- 计算机怎么更改网络密码,该如何修改自家宽带帐号的密码?
- 虚拟机服务器安装iis报错,Windows2008R2安装iis和iis下搭建web服务器(9.18 第七天)...
- java 调用ejb_一步一步教你远程调用EJB
- Activex控件是什么?