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折交叉验证法和留一法相关推荐

  1. 周志华西瓜书3.4题——用十折交叉验证法和留一法估计对率回归的误差

    周志华西瓜书3.4题. 本文所编写的代码均使用python3.7进行调试,依靠的sklearn进行的实验. 第一步,导入iris数据集,数据集使用sklearn包里面自带的. from sklearn ...

  2. 周志华《机器学习》课后习题3.410折交叉验证法和留一法UCI实例比较

    3.4选择两个UCI数据集,比较10折交叉验证法和留一法所估计出的对率回归的错误率. 利用SciKitLearn做十折交叉验证和留一法筛选 本文选用UCI提供的鸢尾花数据集和红酒产地数据集. Iris ...

  3. 《机器学习》课后习题 3.4 选择两个 UCI 数据集,比较 10 折交叉验证法和留 法所估计出的对率回归的错误率.

    参考了han同学的答案,数据集也可在han同学的github上下载. 3.4 选择两个 UCI 数据集,比较 10 折交叉验证法和留 法所估计出的对率回归的错误率. import numpy as n ...

  4. 机器学习(MACHINE LEARNING)交叉验证(简单交叉验证、k折交叉验证、留一法)

    文章目录 1 简单的交叉验证 2 k折交叉验证 k-fold cross validation 3 留一法 leave-one-out cross validation 针对经验风险最小化算法的过拟合 ...

  5. 《机器学习》周志华课后习题答案——第三章 (1-7题)

    <机器学习>周志华课后习题答案--第三章 (1-7题) 文章目录 <机器学习>周志华课后习题答案--第三章 (1-7题) 一.试析在什么情形下式(3.2)中不必考虑偏置项b. ...

  6. 周志华机器学习课后习题解析【第二章】

    作者 | 我是韩小琦 链接 | https://zhuanlan.zhihu.com/p/42435889 2.1 数据集包含 1000 个样本,其中 500 个正例. 500 个反例,将其划分为包含 ...

  7. 机器学习-周志华-课后习题答案-线性模型

    3.1试分析在什么情况下,在以下式子中不比考虑偏置项b. 答:在线性回归中,所有参数的确定都是为了让残差项的均值为0且残差项的平方和最小.在所有其他参数项确定后,偏置项b(或者说是常数项)的变化体现出 ...

  8. 【吃瓜教程】周志华机器学习西瓜书第三章答案

    线性模型结构梳理 3.1 试析在什么情形下式3.2中不必考虑偏置项b 答案一: 偏置项b在数值上代表了自变量取0时,因变量的取值: 1.当讨论变量x对结果y的影响,不用考虑b: 2.可以用变量归一化( ...

  9. 周志华-机器学习西瓜书-第三章习题3.3 编程实现对率回归

    本文为周志华机器学习西瓜书第三章课后习题3.3答案,编程实现对率回归,数据集为书本第89页的数据 使用tensorflow实现过程 # coding=utf-8 import tensorflow a ...

  10. 《机器学习》周志华课后习题答案——第一章(1-3题完结)

    <机器学习>周志华课后习题答案--第一章 文章目录 <机器学习>周志华课后习题答案--第一章 一.表1.1中若只包含编号为1和4的两个样例,试给出相应的版本空间 二.与使用单个 ...

最新文章

  1. C#中父子窗口之间实现控件互操作
  2. abaqus生成adams柔性体_专栏 | HyperMesh_To_Abaqus接口——模型导入导出问题
  3. 2017.9.23 Count on a tree 思考记录
  4. 华为路由器ospf路由表解读_网络-路由交换-路由基础-华为-OSPF的工作原理
  5. POJ - 3461 (kmp)
  6. [PyTorch] 基于Python和PyTorch的线性拟合
  7. Harmony OS — PageSliderIndicator滑动页面指示器
  8. 【分享】React函数式组件写法优劣
  9. sprintf与swprintf
  10. Oracle RMAN 备份与恢复
  11. 444 nginx_nginx发布静态资源
  12. Android 私有权限白名单
  13. 编写函数求整形数组a中存储的m个不重复的整数的第k大的整数(其中m=1,1=k=m)很简单的一个思路是酱紫的:管他辣么多干啥,上来一把排序然后直接得答案...
  14. 服务器协议 重发 回包 039,3情报板预置播放表、位图一览表.doc
  15. 通过Safari浏览器获取iOS设备UDID(设备唯一标识符)
  16. 天玑9000和苹果a15哪个好
  17. 把kali linux 装进 U盘并实现数据可存储
  18. 数据挖掘之人工神经网络
  19. 快速调整 图片的 像素大小
  20. Linux极简快速入门|Linux操作系统(四)

热门文章

  1. 大数据入门介绍和学习路线
  2. 正交匹配追踪算法OMP
  3. smtp邮件服务器配置,配置SMTP服务器
  4. Java实现网上书店管理系统(idea+MySQL+navicat)
  5. 服务器“**”上的MSDTC不可用的解决办法
  6. 设计师案头必备的配色灵感宝典软件\插件!
  7. 计算机怎么更改网络密码,该如何修改自家宽带帐号的密码?
  8. 虚拟机服务器安装iis报错,Windows2008R2安装iis和iis下搭建web服务器(9.18 第七天)...
  9. java 调用ejb_一步一步教你远程调用EJB
  10. Activex控件是什么?