吃瓜教程|Datawhale-9月(1)

吃瓜教程|Datawhale-9月(1)

绪论

引言

条件→结果

机器学习研究的主要内容是关于计算机上从数据中产生模型(model)的算法,即学习算法(learning algorithm)

基本术语

*只解释我自己不明白的

  • 数据集data set

  • 示例instance/样本sample

  • 属性attribute/特征feature

  • 属性值attribute value

  • 属性空间attribute space/样本空间sample space/输入空间

  • 特征向量feature vector:一个样本在属性形成的多维空间中所属于的点的坐标向量

  • 维数dimensionality:数据集中属性个数

  • 训练数据training data

  • 训练样本training set

  • 假设hypothesis:数据的某种潜在规律

  • 真相/真实ground-truth:某种潜在规律本身

  • 学习器learner:模型

  • 标签/标记label:训练样本的结果信息

  • 标记空间/输出空间label space:所有标记的集合,用Γ表示

  • 样例example:拥有了label的instance,一般用(xi,yi)表示第i个样例,其中yi∈Γ是示例xi的标记

  • 泛化generalization:学习得的模型适用于新样本的能力

  • 分布distribution:假设样本空间中全体样本全部服从的未知规律,D

  • 独立同分布independent and identically distributed(i.i.d):我们获得的每个样本都是独立地从D上采样获取的

假设空间

版本空间

所有可能为假设空间,删除掉与训练集上正例不同的和与反例相同的设下的组成了版本空间。

归纳induction

特殊→一般(泛化)

演绎deduction

一般→特殊(特化)

归纳偏好

机器学习算法在学习的过程中对某种类型假设的偏好

原则:奥卡姆剃刀:选最简单的那个

习题

1-1

# 表1.1中若只包含编号为1和4的两个样例,试给出相应的版本空间。
# 版本空间即在假设空间中找到与正例相同,与反例相反的
# 故思路为:写出假设空间->明确正反例->找出假设空间中与正例相同与反例相反的

import numpy
if __name__ == '__main__':
    # 用16进制表示西瓜的不同种类,共有三种属性,每种属性有三种不同可能情况,故有3*3*3种可能
    # 用二进制表示的话一种属性用00,01和10来表示,由于二进制较长,故转化为16进制表示
    # 其中乌黑:10,青绿:11;稍蜷:10,蜷缩:11:沉闷:10,浊响:11.
    # 下方列表为假设空间
    melon = (0x3f, 0x3d, 0x3e, 0x37, 0x3b, 0x1f, 0x2f, 0x35, 0x36, 0x39, 0x3a, 0x1d, 0x1e, 0x2d,
             0x2e, 0x17, 0x1b, 0x27, 0x2b, 0x15, 0x16, 0x19, 0x1a, 0x25, 0x26, 0x29, 0x2a)
    # 两个样例分别为青绿蜷缩浊响和乌黑稍蜷沉闷
    # 其中前者为正例,后者为反例
    sample = (0x15,0x2a)
    # sum为计数
    sum = 0
    for i in range(0,27):
        # 版本空间:在假设空间中删除与正例不一致的或者与反例一致的假设
        # 即版本空间为和假设空间中反例不一致并且与正例一致的假设
        if( (melon[i] | sample[1] ) != melon[i] and (melon[i] | sample[0]) == melon[i] ):
            sum = sum+1
            print(bin(melon[i]),i+1)
    print(sum)

1-2

# 与使用单个合取式来进行假设表示相比,使用“析合范式”将使得假设空间具有更强的表示能力。
# 若使用最多包含k个合取式的析合范式来表达1.1的西瓜分类问题的假设空间,试估算有多少种可能的假设。
# code:https://blog.csdn.net/qq_40273675/article/details/89856447
# 该代码用了3*4*4个假设基础的思路(另一种为2*3*3)
# 由于(A=a)∨(A=*)与(A=*)等价,故在求出所有假设空间后要将此形式(冗余)的删除
# 思路为:排列组合C(48,k)->检验是否有*->是->除*之外的假设是否被其他的包含。如(AAB)∨(AA*)->是->删除
#                                 ┕>否->不冗余                                   ┕>否->不冗余

import re
import itertools as it

def get_combine_hyps(list_attr, k):
    # 排列组合
    # Without Empty set
    list_hyps = []
    # 有三个特征
    for value_attr0 in list_attr[0]:
        for value_attr1 in list_attr[1]:
            for value_attr2 in list_attr[2]:
                x = value_attr0 + value_attr1 + value_attr2
                list_hyps.append(x)
    list_com = list(it.combinations(list_hyps, k))  # 排列组合C48,k
    return list_com

def delete_repeated(list_in):
    # 删除冗余
    list_outer = []
    list_general = []
    flag_repeating = 0  # 1时为不冗余,0时为冗余

    for com_hyp in list_in:
        """找出每组析合范式中的泛化假设"""
        for a_hyp in com_hyp:
            # 检验是否有*
            if "." in a_hyp:
                # 如果存在则进入下一步,将有*的合取式存入list_general
                list_general.append(a_hyp)
            else:
                pass
        """判断泛化假设是否与包含其他假设"""
        if len(list_general) == 0:
            flag_repeating = 1
        else:
            for b_hyp in com_hyp:
                for general in list_general:
                    # 先排除掉相同的
                    if general == b_hyp:
                        pass
                    else:
                        # re.search 扫描整个字符串并返回第一个成功的匹配,如果没有匹配,就返回一个None。
                        # 返回None时表明没有冗余
                        hyp_re = re.search(general, b_hyp)
                        if hyp_re is None:
                            flag_repeating = 1
                        else:
                            pass
                # 将list_general初始化,否则会出现很多个循环中包含*的项被添加进去的状况
                list_general = []
        if flag_repeating == 1:
            list_outer.append(com_hyp)
            flag_repeating = 0

    return list_outer

def main(k):
    list_attribute = [["A", "B", "."], ["A", "B", "C", "."], ["A", "B", "C", "."]]
    hypothesis = get_combine_hyps(list_attribute, k)
    if k < 1 or k > 48:
        print("k值必须为小于48的正整数!")
    elif k == 1:
        print(len(hypothesis), hypothesis)
    else:
        hyps = delete_repeated(hypothesis)
        print(len(hyps), hyps)

if __name__ == "__main__":
    main(2)

模型评估与选择

经验误差与过拟合

错误率:样本个数m中有a个错误样本,则错误率E=am ,精度为1−am

误差:预测输出和真实输出之间的差异

经验误差:学习器在训练集上的误差,也称训练误差

过拟合:学习器把训练数据本身特性当成了所有潜在样本的一般特性,导致泛化性不高。

评估方法

测试集

  • 留出法

    直接将数据集划分为两个互斥的集合(正反例比例一致)

  • K折交叉验证

  • 留一法(Leave-One-Out,简称LOO):每次只使用一个作为测试集,剩下的全部作为训练集

  • 自助法

    一个样本在m次采样中始终不被采到的概率为(1−1m)m 取极限:

    \[\lim_{m \to \infty} (1-\frac{1}{m} )^{m} =\frac{1}{e}≈0.368 \]

验证集

训练集→验证集

↑ 调参 ↓

性能度量

均方误差(最常使用)

错误率与精度

  • 错误率:错误的比率

  • 精度:1-错误率

查准率、查全率与F1

  • 混淆矩阵:真正例(TP)、假正例(FP)、真反例(TN)、假反例(FN)组成的分类结果表。

  • 查准率P:预测是正例的当中,真正例的概率

  • 查全率R:真正例中,被预测为正例的概率

一般来说,这两个是矛盾的变量,一方高的情况,另一方会低。

  • 查准率-查全率曲线:简称P-R曲线

比较两个模型可以考虑比较平衡点

  • 平衡点:查准率=查全率的点

\[F1=\frac{2\times P\times R}{P+R}=\frac{2\times TP}{样例总数+TP-TN} \]

F1是基于查准率和查全率的调和平均定义的

\[\frac{1}{F1}=\frac{1}{2}\cdot (\frac{1}{P}+\frac{1}{R}) \]

\(F_\beta\)是加权调和平均

\[\frac{1}{F_\beta }=\frac{1}{1+\beta ^2}\cdot (\frac{1}{P}+\frac{\beta ^2}{R}) \]

\[F_\beta=\frac{(1+\beta ^2)\times P\times R}{(\beta ^2\times P)+R} \]

其中β>0度量了查全率对查准率的相对重要性,β>1时查全率更有影响,β<1时查准率更有影响,β=1时为标准F1。

在多个混淆矩阵中(多次训练或者多组数据得到)考虑查准率和查全率可以用宏查准率(macro-P)宏查全率(macro-R)以及宏F1(macro-F1)

\[macro-P=\frac{1}{n}\sum_{n}^{i=1}P_i \]

\[macro-R=\frac{1}{n}\sum_{n}^{i=1}R_i \]

\[macro-F1=\frac{2\times macro-P\times macro-R}{macro-P+macro-R} \]

习题

2-1

数据集包含1000个样本,其中500个正例、500个反例,将其划分为包含70%样本的训练集和30%的样本测试集用于留出法评估,试估算有多少划分方式。

因为要保持分布一致性,故分出500 * 70%个正例样本和反例样本去训练集,分出500 * 30%个正例样本和反例样本去测试集,故划分方式有 \(C_{500}^{350}\times C_{500}^{350}=C_{500}^{150}\times C_{500}^{150}\) 个。

2-2

数据集包含100个样本,其中正反例各一半,假定学习算法所产生的模型是将新样本预测为训练样本数较多的类别(训练样本数相同时进行随机猜测),试给出用10折交叉验证法和留一法分别对错误率进行评估所得的结果。

10折交叉验证法中因为正反例各一半故错误率为50%

留一法:因为正反例各一半,无论取走哪一个,剩下的同类的必然为少数,故预测一定是错误的,故错误率为1

2-3

若学习器A的F1值比学习器B高,试析A的BEP值是否也比B高。

在P-R图中,每个点都可以有F1值,但是BEP只有一个,即P=R时,故两者没有什么太大关系。

posted @ 2021-09-13 15:21  ryukirin  阅读(123)  评论(0编辑  收藏  举报