【西瓜书】模型评估与选择

模型评估

错误率&精度

m个样本,其中有a个分类错误;
错误率(error rate): E = a m E=\frac{a}{m} E=ma

精度(accuracy): 1 − a m 1-\frac{a}{m} 1ma

误差

误差:学习器的实际预测输出与样本的真实输出之间的差异。
训练误差(经验误差):学习器在训练集上的误差。
泛化误差:学习器在新样本上的误差。

过拟合&欠拟合

过拟合:学习器把训练样本自身的特点当成了所有潜在样本具有的一般性质,导致泛化性能下降的现象,一般由于学习器学习能力过强造成。
欠拟合:过拟合的相对面,指学习器对训练样本的一般性质尚未能掌握,一般由于学习器学习能力低下造成。

评估方法

实验测试法:使用一个与训练集互斥的、从样本真实分布中独立同分布采样而获得的数据集作为测试集,以测试集上的测试误差近似作为泛化误差,用以评估模型好坏。

处理数据集的方法
留出法

定义:直接将数据集D 划分为两个互斥的集,一个为训练集S,一个为测试集T,即D=S∪T,S∩T=Ø。
示例:D包含1000个样本,将其划分为S包含700个样本,T包含300个样本。

注:由于要保持S和T的分布的一致性,从采样的角度,通常采用分层采样的方式,即保留类别比例的采样方式。假设D有500正例,500反例,那么S将包含350正例,350反例,T将包含150正例,150反例。

缺点:留出法需要划分S与T的比例,如果S的比例过大,将会导致T较小,评估结果不准确,如果S比例过小,则S与D有较大差别,从而降低评估的准确性。

注:一般做法是将大约 2 3 \frac{2}{3} 32~ 4 5 \frac{4}{5} 54的样本用于训练。

交叉验证法(k折交叉验证)

定义:将数据集D分为k个互斥、大小相似的子集,即D=D1∪D2∪…∪Dk,Di∩Dj=Ø(i≠j)。每个子集分布一致。每次选取k-1个子集的并集作为训练集,余下的子集作为测试集。这样我们可以得到k次训练和测试的结果,最终返回k次结果的均值。

注:k常取10。为了减少因划分而产生的误差,k折交叉验证通常要使用不同的划分重复p次,最终的评估结果是这p次的均值。常见的有10次10折交叉验证法。

留一法:k折交叉验证的特例。当样本数为m,k=m时,每个子集只含有一个样本。
优点:训练集只比初始数据集少一个样本,因此在绝大多数情况下,留一法被实际评估的模型与期望评估用的D训练出的模型很相似。留一法的评估结果往往认为比较准确。
缺点:当样本量过大时,计算开销是难以忍受的。

自助法(bootstrapping)

自主采样(bootstrap sampling):给定包含m个样本的数据集D,我们对其进行采样产生数据集D’:每次随机从D中挑选一个样本,将其拷贝放入D’,然后再将该样本放回初始数据集D中,使得该样本在下次采样时任可能被采到;这个过程重读执行m次我们就得到包含m个样本的数据集D’。

注:样本在m次采样中不被采到的概率是(1- 1 m \frac{1}{m} m1)m,取极限得 lim ⁡ m → ∞ ( 1 − 1 m ) \lim\limits_{m\rightarrow\infty}(1-\frac{1}{m}) mlim(1m1)m= 1 e \frac{1}{e} e1≈0.386

自助法:在数据集D中,通过自主采样获得D’,我们将D’作为训练集,D\D’作为测试集。实际评估模型与期望评估模型都有m个训练样本。这样的测试结果也叫做“外包估计(out-of-bag estimate)”;
优点:在数据集较小、难以有效划分数据集和训练集时很有用,对于集成学习等方法有很大好处。
缺点:自助法产生的数据集改变了原有数据集的分布,会引入估计偏差。

性能度量

最小化错误次数

均方误差

给定样例集D={(x1,y1),(x2,y2),…,(xm,ym)},其中yi是示例xi的真实标记,f(x)是学习器f学习的结果。
均方误差:E(f;D)= 1 m \frac{1}{m} m1 ∑ i = 1 m \sum_ {i=1}^m i=1m( f( xi ) - yi )2

对于

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是用Python实现的西瓜id3决策树模型的代码: ```python import math import pandas as pd class Node: ''' 决策树节点类 ''' def __init__(self, col=-1, value=None, results=None, tb=None, fb=None): self.col = col # 待检验的判断条件所对应的列索引值 self.value = value # 为了使结果为True,当前列必须匹配的值 self.results = results # 存储叶节点上的结果,是一个字典形式,键为类别,值为次数 self.tb = tb # 左子树 self.fb = fb # 右子树 def load_data(): ''' 加载西瓜数据集,返回特征数据和标签 ''' data = pd.read_csv('watermelon.csv') return data.iloc[:, 1:-1], data.iloc[:, -1] def calc_entropy(labels): ''' 计算数据集的熵 ''' total = len(labels) counts = {} for label in labels: if label not in counts: counts[label] = 0 counts[label] += 1 entropy = 0.0 for key in counts: p = counts[key] / total entropy -= p * math.log2(p) return entropy def split_data(data, labels, col, value): ''' 根据给定特征划分数据集 ''' tb_rows, fb_rows = [], [] for i in range(len(data)): row = list(data.iloc[i]) if row[col] == value: tb_rows.append(row + [labels[i]]) else: fb_rows.append(row + [labels[i]]) return pd.DataFrame(tb_rows, columns=data.columns.tolist() + ['label']), pd.DataFrame(fb_rows, columns=data.columns.tolist() + ['label']) def build_tree(data, labels): ''' 构建决策树 ''' if len(labels) == 0: return Node() current_entropy = calc_entropy(labels) best_gain = 0.0 best_criteria = None best_sets = None feature_num = len(data.columns) for col in range(feature_num): column_values = set(data.iloc[:, col]) for value in column_values: tb_data, fb_data = split_data(data, labels, col, value) p = len(tb_data) / len(data) gain = current_entropy - p * calc_entropy(tb_data['label']) - (1 - p) * calc_entropy(fb_data['label']) if gain > best_gain and len(tb_data) > 0 and len(fb_data) > 0: best_gain = gain best_criteria = (col, value) best_sets = (tb_data, fb_data) if best_gain > 0: tb = build_tree(best_sets[0], best_sets[0]['label']) fb = build_tree(best_sets[1], best_sets[1]['label']) return Node(col=best_criteria[0], value=best_criteria[1], tb=tb, fb=fb) else: return Node(results={label: len([label for label in labels if label == '是']), '否': len([label for label in labels if label == '否'])}) def classify(sample, tree): ''' 使用决策树对单个样本进行分类 ''' if tree.results is not None: return tree.results else: v = sample[tree.col] branch = None if v == tree.value: branch = tree.tb else: branch = tree.fb return classify(sample, branch) def predict(data, tree): ''' 对数据集进行分类 ''' return [classify(list(data.iloc[i]), tree) for i in range(len(data))] data, labels = load_data() tree = build_tree(data, labels) print(predict(data, tree)) ``` 这里使用了pandas库来读取数据集,需要将数据集放在与代码文件相同的目录下,并命名为watermelon.csv。函数load_data返回的是特征数据和标签,分别是DataFrame类型和Series类型。函数build_tree实现了id3算法,返回构建好的决策树。函数classify用于对单个样本进行分类,函数predict用于对整个数据集进行分类。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值