zoukankan      html  css  js  c++  java
  • 机器学习 第一章-总结

    1、表中若只包含编号为1,4的两个样例,试给出相应的版本空间。

    编号 色泽 根蒂   敲声 好瓜
    1 青绿 蜷缩   浊响
    2 乌黑 蜷缩 浊响
    3 青绿 硬挺 清脆
    4 乌黑 稍蜷 沉闷

    定义:假设空间指的是问题所有假设组成的空间,我们可以把学习过程看作是在假设空间中搜索的过程,搜索目标是寻找与训练集“匹配”的假设。

    假设数据集有n种属性,第i个属性可能的取值有tii(ti+1)i(ti+1)i(ti+1)i(ti+1)种,加上该属性的泛化取值(*),所以可能的假设有πi(ti+1)。再用空集表示没有正例,假设空间中一共πi(ti+1)+1种假设。
    现实问题中常面临很大的假设空间,我们可以寻找一个与训练集一致的假设集合,称之为版本空间。版本空间从假设空间剔除了与正例不一致和与反例一致的假设,它可以看成是对正例的最大泛化。

    版本空间的可以通过搜索假设空间来得到,这样需要遍历完整的假设空间。如果数据集中有正例,则可以先对一个正例进行最大泛化,得到2n个假设,然后再对这些假设进行剔除操作,可以适当精简计算量。
    西瓜数据集(精简)

    编号色泽根蒂敲声好瓜
    1 青绿 蜷缩 浊响
    2 乌黑 稍蜷 沉闷

    数据集有3个属性,每个属性2种取值,一共3*3*3+1=28种假设,分别为

    • 1.色泽=青绿  根蒂=蜷缩   敲声=浊响
    • 2.色泽=青绿  根蒂=蜷缩   敲声=沉闷
    • 3.色泽=青绿  根蒂=稍蜷   敲声=浊响
    • 4.色泽=青绿  根蒂=稍蜷   敲声=沉闷
    • 5.色泽=乌黑  根蒂=蜷缩   敲声=浊响
    • 6.色泽=乌黑  根蒂=蜷缩   敲声=沉闷
    • 7.色泽=乌黑  根蒂=稍蜷   敲声=浊响
    • 8.色泽=乌黑  根蒂=稍蜷   敲声=沉闷
    • 9.色泽=青绿  根蒂=蜷缩   敲声=*
    • 10.色泽=青绿 根蒂=稍蜷   敲声=*
    • 11.色泽=乌黑 根蒂=蜷缩   敲声=*
    • 12.色泽=乌黑 根蒂=稍蜷   敲声=*
    • 13.色泽=青绿 根蒂=*        敲声=浊响
    • 14.色泽=青绿 根蒂=*        敲声=沉闷
    • 15.色泽=乌黑 根蒂=*        敲声=浊响
    • 16.色泽=乌黑 根蒂=*        敲声=沉闷
    • 17.色泽=*  根蒂=蜷缩   敲声=浊响
    • 18.色泽=*  根蒂=蜷缩   敲声=沉闷
    • 19.色泽=*  根蒂=稍蜷   敲声=浊响
    • 20.色泽=*  根蒂=稍蜷   敲声=沉闷
    • 21.色泽=青绿 根蒂=*        敲声=*
    • 22.色泽=乌黑 根蒂=*        敲声=*
    • 23.色泽=*  根蒂=蜷缩   敲声=*
    • 24.色泽=*  根蒂=稍蜷   敲声=*
    • 25.色泽=*  根蒂=*        敲声=浊响
    • 26.色泽=*  根蒂=*        敲声=沉闷
    • 27.色泽=*  根蒂=*        敲声=*
    • 28.空集Ø 编号1的数据可以删除

           编号1的数据可以删除2-8,10-12,14-16,18-20,22,24,62,28 (不包含数据1) 

           编号1的数据可以删除27(包含了数据2)

      • 所以版本空间为:
    • 1.色泽=青绿  根蒂=蜷缩   敲声=浊响
    • 9.色泽=青绿  根蒂=蜷缩   敲声=*
    • 13.色泽=青绿 根蒂=*        敲声=浊响
    • 17.色泽=*  根蒂=蜷缩   敲声=浊响
    • 21.色泽=青绿 根蒂=*        敲声=*
    • 23.色泽=*  根蒂=蜷缩   敲声=*
    • 25.色泽=* 根蒂=* 敲声=浊响

     一般情况下版本空间是正例的泛化,但由于数据集中只有1个正例,所以在版本空间中依然包含了这个样本的假设(假设1)。

    2、与使用单个合取式来进行假设表示相比,使用“析合范式”将使得假设空间具有更强的表示能力。若使用最多包含k个合取式的析合范式来表达1.1的西瓜分类问题的假设空间,试估算有多少种可能的假设。

    表包含4个样例,3种属性,假设空间中有344+1=49种假设。在不考虑沉余的情况下,最多包含k个合取式来表达假设空间,显然k的最大值是49,每次从中选出k个来组成析合式,共ΣCk49=249 种可能。但是其中包含了很多沉余的情况(至少存在一个合取式被剩余的析合式完全包含<空集除外>)。

    如果考虑沉余的情况 
    在这里忽略空集,一个原因是并不是太明白空集是否应该加入析合式,另外就算需要加入,求出了前面48种假设的组合,可以很容易求出加入空集后的组合数(每种可能都可以加上空集,再加上1种空集单独的情况)。 
    48种假设中: 
    具体假设:233=18种 
    一个属性泛化假设:23+33+23=21种 
    两个属性泛化假设:2+3+3=8种 
    三属性泛化:1种 
    当k=1时,任选一种假设都可以作为一种没有沉余的假设,共48种。 
    k的最大值是18,当k等于18时,就是18种具体属性假设的析取式,共1种。 
    当k取中间值时,就不好分析了。 
    一种可行的算法: 
    由于属性泛化后,一个泛化的假设可以对应多个具体假设。 
    把所有假设按三属性泛化,二属性泛化,一属性泛化,具体属性排序(这样可以保证排在后面的假设不会包含前面的任何一个假设,所以省略了一些包含判断),进行循环枚举,按顺序遍历所有假设组合248种可能(当然绝大部分都提前结束了,不会是那么夸张的量级,虽然也不低):

    • 使用栈来实现非递归,如果当前假设还有没被析合式所包含的具体假设,则认为可以入栈,并当前栈大小的长度计数加1,并继续扫描。
    • 如果当前扫描已经到了最后一个假设,或者所有具体假设已经被全部包含,则退栈。
    • 循环结束条件:当最后一个假设作为第一个压入栈的元素时,认为已经遍历结束。

    由于一共有18种具体假设,可以用一个32位整型(变量为hypos_cur)的后18位来表示每一个具体假设。用1表示具体假设没被包含,用0表示具体假设已经被析合式包含。初始的析合式为空,可以设初试值为0X3FFFF。每个假设也对应一个32位整型(假设变量为hypo_const),代表着它所对应了哪些具体假设,如果它包含了某种具体假设,则该位为1

    • 判断析合式是否包含了全部的具体假设:hypos_cur=0
    • 判断该假设是否已经被析合范式包含:用hypo_const与hypos_cur做与运算(结果用hypo_tmp表示),如果为0表示已经被包含(判断该假设是否包含了当前的析合式:用hypo_const与hypos_cur做或运算,如果为0X3FFFFF,则认为该假设包含了当前析合式,但由于前面对所有假设做了排序,不可能出现这种情况,所以可以省略该判断)。
    • 当某个假设加入析合范式后(入栈)用hypos_cur与hypo_tmp做异或运算,来更改析合式所包含的具体假设。
    • 出栈时再次用hypos_cur与hypo_tmp做异或,回到加入该假设前的情况。
    • 因为是指数级遍历的算法,所以很慢。 
    #include <vector>
    #include <stack>
    using namespace std;
    
    //按泛化程度排序,保证排在后面的假设不会不会包含前面的任何一个假设
    static const char list[] = {
        0,0,0,
        0,0,1,0,0,2,0,0,3,0,1,0,0,2,0,0,3,0,1,0,0,2,0,0,
        0,1,1,0,1,2,0,1,3,0,2,1,0,2,2,0,2,3,0,3,1,0,3,2,0,3,3,
        1,0,1,1,0,2,1,0,3,2,0,1,2,0,2,2,0,3,
        1,1,0,1,2,0,1,3,0,2,1,0,2,2,0,2,3,0,
        1,1,1,1,1,2,1,1,3,1,2,1,1,2,2,1,2,3,1,3,1,1,3,2,1,3,3,
        2,1,1,2,1,2,2,1,3,2,2,1,2,2,2,2,2,3,2,3,1,2,3,2,2,3,3
    };
    
    //用来派生的抽象类
    class hypos {
    public:
        virtual int insert(int cur) = 0;
    };
    
    //单个的假设类
    /*
    hypo_const  假设对应的具体假设集合
    */
    class hypo :public hypos {
    public:
        hypo(int a, int b, int c) {
            hypo_const = 0;
            vector<char>  p[3];
            if (a == 0) {
                p[0].push_back(1);
                p[0].push_back(2);
            }
            else
                p[0].push_back(a);
            if (b == 0) {
                p[1].push_back(1);
                p[1].push_back(2);
                p[1].push_back(3);
            }
            else
                p[1].push_back(b);
            if (c == 0) {
                p[2].push_back(1);
                p[2].push_back(2);
                p[2].push_back(3);
            }
            else
                p[2].push_back(c);
            for (unsigned int i = 0;i < p[0].size();i++)
                for (unsigned int j = 0;j < p[1].size();j++)
                    for (unsigned int k = 0;k < p[2].size();k++)
                        hypo_const |= (1 << (p[0][i] * 9 + p[1][j] * 3 + p[2][k] - 13));
        }
    
        //判断是否要加入到析合式 如果还有具体假设没被包含,则加入
        int insert(int cur) {
            return (hypo_const & cur);
        };
    
    private:
        int hypo_const;
    };
    
    //用于压入栈的派生类 用来实现非递归
    /*
    hypo_tmp    记录这个假设入栈时,带入了哪些具体假设,出栈时要还原
    ptr         记录入栈时的位置
    */
    class hypo_ss :public hypos {
    public:
        hypo_ss(int _ptr,int tmp){
            hypo_tmp = tmp;
            ptr = _ptr;
        }
        int insert(int cur) {
            return 0;
        };
        int hypo_tmp;
        int ptr;
    };
    
    //用来循环遍历的类
    /*
    sum     各个长度的析合式各有多少种可能
    ss      用来实现非递归的栈
    hypos_cur   当前没被包含的具体假设 初始值为0X3FFFF
    hyposs  48个假设集合
    */
    class Traversal :public hypos {
    public:
        Traversal() {
            hypos_cur = 0x3ffff;
            for(int i=0;i<48;i++)
                hyposs.push_back(hypo(list[3*i], list[3*i+1], list[3*i+2]));
        }
    
        //循环顺序遍历的主体
        //cur  初试的位置 设为0
        int insert(int cur) {
            //当前指向的位置
            int ptr = cur;
            while (1) {
                //退出条件 当最后一个假设作为第一个入栈的元素 表示遍历完成
                if (ptr > 47 && !ss.size()) break;
                //回退条件  扫描到最后或者所有具体假设都被包含 
                if (hypos_cur == 0 || ptr>47) {
                    hypo_ss hypo_tmp = ss.top();
                    hypos_cur ^= hypo_tmp.hypo_tmp;
                    ptr = hypo_tmp.ptr + 1;
                    ss.pop();
                    continue;
                }
    
                //入栈条件  如果该假设还有未被包含的具体假设 则入栈,并当前栈大小的计数加1
                if (int tmp =hyposs[ptr].insert(hypos_cur)) {
                    hypos_cur ^= tmp;
                    ss.push(hypo_ss(ptr, tmp));
                    if (sum.size() < ss.size())
                        sum.push_back(0);
                    sum[ss.size() - 1]++;
                }
                ptr++;
            }
            return 1;
        };
        //输出各个长度的可能数
        void print() {
            for (unsigned int i = 0;i < sum.size();i++)
                printf("length %d : %d
    ", i + 1, sum[i]);
        }
    private:
        vector<int> sum;
        stack<hypo_ss> ss;
        int hypos_cur;
        vector<hypo> hyposs;
    };
    
    int main()
    {
        Traversal traversal;
        traversal.insert(0);
        traversal.print();
        system("pause");
        return 0;
    }
    
    /*
    最终输出:
    length 1 : 48
    length 2 : 931
    length 3 : 10332
    length 4 : 72358
    length 5 : 342057
    length 6 : 1141603
    length 7 : 2773332
    length 8 : 4971915
    length 9 : 6543060
    length 10 : 6175660
    length 11 : 4003914
    length 12 : 1676233
    length 13 : 422676
    length 14 : 61884
    length 15 : 5346
    length 16 : 435
    length 17 : 27
    length 18 : 1
    */
    

    3、若数据包含噪声,则假设空间中可能不存在与所有训练样本都一致的假设。在此情形下,试设计一种归纳偏好用于假设选择

    通常认为两个数据的属性越相近,则更倾向于将他们分为同一类。若相同属性出现了两种不同的分类,则认为它属于与他最临近几个数据的属性。也可以考虑同时去掉所有具有相同属性而不同分类的数据,留下的数据就是没误差的数据,但是可能会丢失部分信息。

    4、在论述“没有免费的午餐”定理时,默认使用了“分类错误率”作为性能度量来对分类器进行评估。若换用其他性能度量l,试证明没有免费的午餐”定理仍成立

    考虑二分类问题,NFL首先要保证真是目标函数f均匀分布,对于有X个样本的二分类问题,显然f共有2X种情况。其中一半是与假设一致的,也就 P(f(x)=h(x))=0.5。 
    此时, fl(h(x),f(x))=0.52X(l(h(x)=f(x))+l(h(x)f(x))) 
    l(h(x)=f(x))+l(h(x)f(x))应该是个常数,隐含的条件就该是(一个比较合理的充分条件) l(0,0)=l(1,1),l(1,0)=l(0,1)。如果不满足, NFL 应该就不成立了(或者不那么容易证明)。

    5、试述机器学习在互联网搜索的哪些环节起什么作用

    1. 最常见的,消息推送,比如某东经常说某些商品我可能会感兴趣,然而并没有。 
    2. 网站相关度排行,通过点击量,网页内容进行综合分析。 
    3. 图片搜索,现在大部分还是通过标签来搜索,不过基于像素的搜索也总会有的吧。
  • 相关阅读:
    20190912
    20190825
    20190818
    20190811
    20190804
    数据结构与算法之顺序表
    数据结构与算法之顺序表
    数据结构与算法之单链表
    数据结构与算法之循环双链表
    数据结构与算法之循环单链表
  • 原文地址:https://www.cnblogs.com/sirius-swu/p/6890005.html
Copyright © 2011-2022 走看看