機器學習(周志華) 參考答案 第一章 緒論 1.2
阿新 • • 發佈:2019-02-13
機器學習(周志華) 參考答案 第一章 緒論 1.2
機器學習(周志華西瓜書) 參考答案 總目錄
機器學習(周志華) 參考答案 第一章 緒論
2.與使用單個合取式來進行假設表示相比,使用“析合正規化”將使得假設空間具有更強的表示能力。若使用最多包含k個合取式的析合正規化來表達1.1的西瓜分類問題的假設空間,試估算有多少種可能的假設。
表1.1包含4個樣例,3種屬性,假設空間中有種假設。在不考慮沉餘的情況下,最多包含k個合取式來表達假設空間,顯然k的最大值是49,每次從中選出k個來組成析合式,共 種可能。但是其中包含了很多沉餘的情況(至少存在一個合取式被剩餘的析合式完全包含<空集除外>)。
如果考慮沉餘的情況
在這裡忽略空集,一個原因是並不是太明白空集是否應該加入析合式,另外就算需要加入,求出了前面48種假設的組合,可以很容易求出加入空集後的組合數(每種可能都可以加上空集,再加上1種空集單獨的情況)。
48種假設中:
具體假設:種
一個屬性泛化假設:種
兩個屬性泛化假設:種
三屬性泛化:種
當k=時,任選一種假設都可以作為一種沒有沉餘的假設,共種。
k的最大值是,當k等於時,就是種具體屬性假設的析取式,共 種。
當k取中間值時,就不好分析了。
一種可行的演算法:
由於屬性泛化後,一個泛化的假設可以對應多個具體假設。
把所有假設按三屬性泛化,二屬性泛化,一屬性泛化,具體屬性排序(這樣可以保證排在後面的假設不會包含前面的任何一個假設,所以省略了一些包含判斷),進行迴圈列舉,按順序遍歷所有假設組合種可能(當然絕大部分都提前結束了,不會是那麼誇張的量級,雖然也不低):
- 使用棧來實現非遞迴,如果當前假設還有沒被析合式所包含的具體假設,則認為可以入棧,並當前棧大小的長度計數加,並繼續掃描。
- 如果當前掃描已經到了最後一個假設,或者所有具體假設已經被全部包含,則退棧。
- 迴圈結束條件:當最後一個假設作為第一個壓入棧的元素時,認為已經遍歷結束。
由於一共有種具體假設,可以用一個位整型(變數為hypos_cur)的後位來表示每一個具體假設。用1表示具體假設沒被包含,用表示具體假設已經被析合式包含。初始的析合式為空,可以設初試值為。每個假設也對應一個位整型(假設變數為hypo_const),代表著它所對應了哪些具體假設,如果它包含了某種具體假設,則該位為。
- 判斷析合式是否包含了全部的具體假設:hypos_cur=。
- 判斷該假設是否已經被析合正規化包含:用hypo_const與hypos_cur做與運算(結果用hypo_tmp表示),如果為表示已經被包含(判斷該假設是否包含了當前的析合式:用hypo_const與hypos_cur做或運算,如果為,則認為該假設包含了當前析合式,但由於前面對所有假設做了排序,不可能出現這種情況,所以可以省略該判斷)。
- 當某個假設加入析合正規化後(入棧)用hypos_cur與hypo_tmp做異或運算,來更改析合式所包含的具體假設。
- 出棧時再次用hypos_cur與hypo_tmp做異或,回到加入該假設前的情況。
- 因為是指數級遍歷的演算法,所以很慢,我的3代i7筆記本大概算了3分鐘。
#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\n", 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
*/