题目:表1.1中若只包含编号为1和4的两个样例,试给出相应的版本空间。
P5:与训练集一致的“假设集合”我们称之为版本空间。本题即在假设空间中搜索包含正例且不包含反例的所有假设。(详细说明见后思考)
首先,用一个六位二进制数将整个假设空间表示出来,每两位描述一个属性。前两位取01表示色泽的取值为“青绿”,10表示色泽取值为“乌黑”,11表示色泽取值为 *。后四位分别表示根蒂与敲声的取值,以此类推.注意题中只包含1和4两个样例,因此假设空间中色泽的取值范围为:* ,乌黑、青绿;根蒂的取值范围为:*,蜷缩、稍蜷;敲声的取值范围为:*,浊响、沉闷。
假设空间
序号 | 色泽 | 根蒂 | 敲声 | 二进制表示 |
---|---|---|---|---|
1 | * | * | * | 111111 |
2 | * | * | 浊响 | 111101 |
3 | * | * | 沉闷 | 111110 |
4 | * | 蜷缩 | * | 110111 |
5 | * | 稍蜷 | * | 111011 |
6 | 青绿 | * | * | 011111 |
7 | 乌黑 | * | * | 101111 |
8 | * | 蜷缩 | 浊响 | 110101 |
9 | * | 蜷缩 | 沉闷 | 110110 |
10 | * | 稍蜷 | 浊响 | 111001 |
11 | * | 稍蜷 | 沉闷 | 111010 |
12 | 青绿 | * | 浊响 | 011101 |
13 | 青绿 | * | 沉闷 | 011110 |
14 | 乌黑 | * | 浊响 | 101101 |
15 | 乌黑 | * | 沉闷 | 101110 |
16 | 青绿 | 蜷缩 | * | 010111 |
17 | 青绿 | 稍蜷 | * | 011011 |
18 | 乌黑 | 蜷缩 | * | 100111 |
19 | 乌黑 | 稍蜷 | * | 101011 |
20 | 青绿 | 蜷缩 | 浊响 | 010101 |
21 | 青绿 | 蜷缩 | 沉闷 | 010110 |
22 | 青绿 | 稍蜷 | 浊响 | 011001 |
23 | 青绿 | 稍蜷 | 沉闷 | 011010 |
24 | 乌黑 | 蜷缩 | 浊响 | 100101 |
25 | 乌黑 | 蜷缩 | 沉闷 | 100110 |
26 | 乌黑 | 稍蜷 | 浊响 | 101001 |
27 | 乌黑 | 稍蜷 | 沉闷 | 101010 |
若两个假设的二进制表示分别为A和B,则 A | B==A ⇒ B⊂A,A&B==B ⇒ B⊂A.(任意一个等式都可以判断出假设A是否包含假设B)
设P为假设1(正例),N为假设4(反例),假设H只要满足H | P==H && H | N != H为真,那么假设H就应该被包含在版本空间内。遍历假设空间内的所有假设进行上述判断,就可以获得版本空间内的所有假设。
#include
int hypo_const[27] = {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};
void main()
{
int sample[2] = {0x15,0x2a},sum=0;
for(int i=0;i<27;i++)
{
if( (hypo_const[i] | sample[1] ) != hypo_const[i] && (hypo_const[i] | sample[0]) == hypo_const[i] )
{
sum++;
printf("%x %d\n",hypo_const[i],i+1);
}
}
printf("\nsum:%d\n\n",sum);
}
求得版本空间为假设2、4、6、8、12、16、20.
版本空间
序号 | 色泽 | 根蒂 | 敲声 | 二进制表示 |
---|---|---|---|---|
2 | * | * | 浊响 | 111101 |
4 | * | 蜷缩 | * | 110111 |
6 | 青绿 | * | * | 011111 |
8 | * | 蜷缩 | 浊响 | 110101 |
12 | 青绿 | * | 浊响 | 011101 |
16 | 青绿 | 蜷缩 | * | 010111 |
20 | 青绿 | 蜷缩 | 浊响 | 010101 |
思考:书中P5提到,版本空间的求法为遍历假设空间,不断删除与正例不一致的假设和(或)与反例一致的假设。按照我的理解,版本空间有以下3种不同的求法。
本题使用了第一种方法来求版本空间,三种求法的选择应该属于归纳偏好的范畴。
题目:与使用单个合取式来进行假设表示相比,使用“析合范式”将使得假设空间具有更强的表示能力。若使用最多包含k个合取式的析合范式来表达表1.1西瓜分类问题的假设空间,试估算有多少种可能的假设。
分析:本题可以延续上一题的假设表述方法,每个合取式用一个8位二进制整数来表示,则一共有48个数待选。遍历C(48,k)种可能的选取组合,求出每种组合中k个合取式的合并结果,再去掉重复和冗余的情况,就是包含k个合取式的析合范式所能表达的假设空间大小。请注意,题目所述为“最多包含k个合取式的析合范式”,也就是说1,2,3…k个合取式组成的析合范式都满足条件,而不是仅考虑k个合取式组成的析合范式。
难点:
1. 假设空间太大,穷举所有组合不现实。
2. 合取式的合并结果(析取式)如何求,如何用一个整数表示。
先来看难点2
前文所述的表示方法,合取式的合并算法十分低效,因此有必要定义一种新的表达方式。在48个基本假设(基本合取式)中,有2*3*3=18个叶子假设(叶子合取式):每个特征的取值都为具体值。任何合取式、析取式都可以用这18个叶子合取式的组合来表示。因此可以用一个18位的二进制整数来表示任意假设:将18个叶子合取式编号,若某假设包含序号为1的叶子合取式,则该假设第一位为1,否则第一位为0。其它位类推。在这种新的表达方式下,合并合取式(或析取式)A,B,只需作 C=A|B 的按位或运算,C即为表示A、B合并析取式的整数。(C语言按位或运算的速度非常快)
新的表达方式下,代表每个假设整数的求法如下:
1.将48个基本合取式的旧表达式存在数组hypo_old中
2.将18个叶子合取式的旧表达式存在数组hypo_leaf中
3.对hypo_old中的每个元素,循环对hypo_leaf中的18个元素xi作如下判断:若A|xi==A,则Anew中第i位为1,否则Anew中第i为为0.
将新的表达结果(48个整数)存在hypo_const中。
这种表达方式不仅大大提高了合并合取式算法的效率,还让我们有了一个额外发现:本题的最大假设空间大小为262143.为什么会有这个结论呢?原因就是18位二进制整数所能表示的最大范围即262143,又因为析取范式不考虑空集∅,即整数不为0,因此假设空间的大小即262143.这个结论非常重要,甚至一定程度上它就是本道题的答案(k足够大)。
难点1
如图所示,以k=3时为例,遍历C(48,3)中所有组合的情况实际上就是3个标记依次不断向右移动的过程。序号大的标记,总是在序号小的标记的右侧。
在移动过程中,我们总是先确定标记1的位置(初始记为1),然后在标记1的右侧确定标记2的位置(初始记为1+1)……直到确定标记k的位置(初始记为k-1+1,这么写有些奇怪,原因下面会讲)。每确定完一次标记k,就形成一次组合。之后,将标记k自增,若标记k≤48,则又形成新的组合,继续自增;若标记k>48,则标记k越界,转而向前先寻找标记k-1的位置(自增),若k-1也越界(标记k-1>47),继续向前寻找标记k-2位置(自增),直到向前寻得标记k-i自增后不越界(标记k-i≤48-i),此时调转趋势,向后寻找标记k-i+1的位置(递增,值为标记k-i的值+1),直到标记k的位置(标记k-1的值+1)。
确定方式:每个标记有两种可能的确定方式。若是从后面的标记越界返回,则改变方式为自增,若是从前面的标记顺序向下确定,则改变方式为递增(上一个标记的值+1)。额外规定:1.形成一次组合后,标记k的改变方式为自增。2.标记1的改变方式总为自增。
优化方法:
动态申请长度为k的一维数组poslist和hypo_process,poslist用来保存k个标记的位置,hypo_process用来保存前k个合取式合并的结果。用整数posflag来记录当前需要确定的标记序号。
每次确定完标记poslist[posflag]后(自增并通过越界判断),则将前posflag个合取式的合并结果存进hypo_process[posflag],即hypo_process[posflag]=hypo_process[posflag-1]|hypo_const[poslist[posflag]]
若hypo_process[posflag]==hypo_process[posflag-1] || hypo_process[posflag]==0x3ffff&&posflag
注意:计数前应该判断是否重复。
因为不同的析取范式,有可能表示同一种假设。比如:(色泽=*,根蒂=*,敲声=浊响)∨(色泽=*,根蒂=*,敲声=清脆)∨(色泽=*,根蒂=*,敲声=沉闷)与(色泽=乌黑,根蒂=*,敲声=*)∨(色泽=青绿,根蒂=*,敲声=*)是同一种假设,它们都表示(色泽=*,根蒂=*,敲声=*),它们在18位整数的表示方法下,对应的整数是唯一的。因此,只有原先未出现此数(此假设),才能将其记录并且计数值自增。否则重复,不计数。由于难点1中我们发现假设空间大小为262143,因此申请一个大小为262143的数组hypo_appear来记录每个假设出现与否。出现则数组对应元素记为1,未出现为0。(如果没有求出这个数,则每个数字出现与否只能用一个队列来记录,判断重复的算法效率非常底下,这就是此数的重要性)
最后,分析中已经提到,题目中要求的是“最多包含k个合取式的析合范式”,因此在for循环中让k从1变到18,执行18次count,在k增加时,hypo_appear中的内容不清空,且计数n_count不归零,就能包含1,2……k个合取式的情况。
代码如下,运行时间在5秒左右:
#include
int hypo_old[48] = {0xff,0xf9,0xfa,0xfc,0xcf,0xd7,0xe7,0x7f,
0xbf,0xc9,0xca,0xcc,0xd1,0xd2,0xd4,0xe1,
0xe2,0xe4,0x79,0x7a,0x7c,0xb9,0xba,0xbc,
0x4f,0x57,0x67,0x8f,0x97,0xa7,0x49,0x4a,
0x4c,0x51,0x52,0x54,0x61,0x62,0x64,0x89,
0x8a,0x8c,0x91,0x92,0x94,0xa1,0xa2,0xa4};
int hypo_leaf[18] = {0x49,0x4a,
0x4c,0x51,0x52,0x54,0x61,0x62,0x64,0x89,
0x8a,0x8c,0x91,0x92,0x94,0xa1,0xa2,0xa4};
int hypo_const[48]= {0};
int new_leaf[18] = {0x20000,0x10000,
0x08000,0x04000,0x02000,0x01000,
0x00800,0x00400,0x00200,0x00100,
0x00080,0x00040,0x00020,0x00010,
0x00008,0x00004,0x00002,0x00001};
int count(int n_n,int n_k,int &n_count,int *hypo_appear)
{
// n_count=0;
int i;
// for(i=0;i<262143;i++)
// hypo_appear[i] = 0;
int *poslist,*hypo_process,posflag,trend;
poslist = new int[n_k];
hypo_process = new int[n_k];
for(i=0;i1;
}
posflag = 0;
while(1)//poslist[0] <= n_n-n_k
{
if(posflag == 0) //如果是第一个则自增,如果超出则退出,否则直接赋值,赋值后如未达个数提前到0x3ffff跳过该点,否则进入下一轮
{
poslist[posflag]++;
if(poslist[0] > n_n-n_k)
break;//*****整个循环的退出口*****//
hypo_process[posflag] = hypo_const[poslist[posflag]]; //直接赋值
if(hypo_process[posflag] == 0x3ffff && posflag1)//提前到0x3ffff跳过
continue;
else
{
posflag++;
trend = 1;//上升趋势
}
}
else //上升趋势递增,下降趋势自增,如果超出则位数下降回滚上一轮,否则加入本轮假设,若无变化则跳过该点,如果未达个数提前到0x3ffff也跳过该点,否则进入下一轮
{
if(trend == 1)
poslist[posflag] = poslist[posflag-1] + 1;
else
poslist[posflag]++;
if(poslist[posflag] > n_n-n_k+posflag)//超出则位数下降
{
posflag--;
trend = 0;
continue;
}
hypo_process[posflag] = hypo_process[posflag-1] | hypo_const[poslist[posflag]];//加入本轮假设
if(hypo_process[posflag] == hypo_process[posflag-1] || hypo_process[posflag] == 0x3ffff && posflag1) //跳过部分
{
trend = 0;//跳过等同回滚,自增
continue;
}
posflag++;
trend = 1;
}
if(posflag == n_k)//说明k个析合范式已经全部形成
{
posflag--;
trend = 0;
if(hypo_appear[hypo_process[posflag]-1]==0)
{
n_count++;
hypo_appear[hypo_process[posflag]-1] = 1;
}
//错误写法:n_count++;
/* 应该判断是否重复。 不同的析取范式,有可能表示同一种假设。 比如:(色泽=*,根蒂=*,敲声=浊响)∨(色泽=*,根蒂=*,敲声=清脆)∨(色泽=*,根蒂=*,敲声=沉闷) 与(色泽=乌黑,根蒂=*,敲声=*)∨(色泽=青绿,根蒂=*,敲声=*)是同一种假设, 它们都表示(色泽=*,根蒂=*,敲声=*),它们在18位整数的表示方法下,对应的整数是唯一的。 因此,只有在原先未出现此数(此假设)的情况下,才能将计数值自增。否则重复,不计数。 */
}
}
delete poslist;
delete hypo_process;
return n_count;
}
void main()
{
for(int i=0;i<48;i++)//难点2,形成新表达式
{
for(int j=0;j<18;j++)
{
if( (hypo_old[i] | hypo_leaf[j]) == hypo_old[i])
hypo_const[i] |= new_leaf[j];
}
}
int change = 0,temp;
int n_count=0;
int *hypo_appear = new int[262143];
for(i=0;i<262143;i++)
hypo_appear[i] = 0;
for(i=1;i<=18;i++)
{
count(48,i,n_count,hypo_appear);
printf("length %-2d : %-10d\n",i,n_count);
}
}
/* length 1 : 48 length 2 : 897 length 3 : 8385 length 4 : 41742 length 5 : 115821 length 6 : 201303 length 7 : 248853 length 8 : 260787 length 9 : 262143 length 10 : 262143 length 11 : 262143 length 12 : 262143 length 13 : 262143 length 14 : 262143 length 15 : 262143 length 16 : 262143 length 17 : 262143 length 18 : 262143 */
可以看到,使用最多包含9个合取式的析合范式,就可以表示整个假设空间。
如果对“只包含 k个合取式的析合范式”这个问题感兴趣,那么将27,29,30行的注释去掉即可。答案如下:
length 1 : 48
length 2 : 865
length 3 : 8028
length 4 : 39861
length 5 : 109686
length 6 : 186102
length 7 : 216036
length 8 : 197362
length 9 : 155382
length 10 : 106762
length 11 : 63004
length 12 : 31180
length 13 : 12616
length 14 : 4048
length 15 : 988
length 16 : 172
length 17 : 19
length 18 : 1
可以看到表示能力最强的是只包含7个合取式的析合范式,但也不能表示出假设空间中所有的262143个假设。当k=18时,只能选取18个叶子合取式才不会产生冗余,因此只能表示(色泽=*,根蒂=*,敲声=*)这一种假设。k>18就没有意义了,因为必定会产生冗余。
题目:若数据包含噪声,则假设空间中有可能不存在与所有训练样本都一致的假设。在此情形下,设计一种归纳偏好用于假设选择。
分析:既然数据中包含噪声,最直接的思路就是首先去除噪声。去噪方法:若存在两个样例属性取值都相同,标记却不同,则只保留标记为正例的样例(或标记为反例的样例,也可以考虑更加复杂的筛选方法,比如统计相似样例的标记),在此基础上求出版本空间。
也可以考虑其他方法:
1.在求版本空间时,只除去与反例不一致的假设。
2.求版本空间时,只留下包含了所有正例的假设。
题目:本章1.4节在论述“没有免费的午餐”定理时,默认使用了“分类错误率”作为性能度量来对分类器进行评估。若换用其他性能度量l,则式(1.1)将改为
试证明“没有免费的午餐定理”仍成立。
证明:
在证明定理之前,先构造一个引理:
引理1:在二分类问题下,对任意性能度量指标 l l , l(h(x)=f(x))+l(h(x)≠f(x))=A,A l ( h ( x ) = f ( x ) ) + l ( h ( x ) ≠ f ( x ) ) = A , A 为某一常数。
证:对于二分类问题,任意性能度量中的正确分类得分与错误分类得分应该是固定的。即:
1.在向搜索引擎提交信息的阶段,能够从提交文本中进行信息提取,进行语义分析。
2.在搜索引擎进行信息匹配的阶段,能够提高问题与各个信息的匹配程度。
3.在向用户展示搜索结果的阶段,能够根据用户对结果感兴趣的程度进行排序。