变形空间和候选消除算法(Candidate-Elimination)C++实现

它能解决FIND-S若干不足之处,FIND-S输出的假设只是H中能拟合训练的多个样例的多个假设中的一个。而在候选消除算法中,输出的是与训练样例一致的所有假设的集合。候选消除算法在描述这一集合时不需要明确列举其所有成员。这也归功于more_general_than偏序结构。在这里需要维护一个一致假设集合的简洁表示,然后在遇到新的训练样例时逐步精化这一表示。

一、表示

定义:一个假设h与训练样例集合D一致,当且仅当对D中每一个样例<x,c(x)>都有h(x)=c(x)。

       Consistent(h,D)≡(∨<x,c(x)>∈D) h(x)=c(x)

定义:关于假设空间H和训练样例集D的变型空间,标记为VSH,D,是H中与训练样例D一致的所有假设构成的子集。

                     VSH,D≡{h∈H|Consistent(h,D)}

2.列表后消除算法(LIST-THEN-ELIMINATE)

       1.变型空间VersionSpace<-包含H中所有假设的列表

   2.对每个训练样例<x,c(x)>

     从变型空间中移除所有h(x)≠c(x)的假设h

       3. 输出VersionSpace中个假设列表

3.变型空间的更简洁表示

定义:关于假设空间H和训练数据D的一般边界(general boundary)G,是在H中与D相一致的极大一般(maximally general)成员的集合。

                     

定义:关于假设空间H和训练数据D的特殊边界(specific  boundary)S,是在H中与D相一致的极大特殊(maximally specific)成员的集合。

       

变型空间的确切组成是:G中包含的假设,S中包含的假设已经G和S直接偏序结果所规定的假设。

定理2.1:变型空间表示定理 令X为任意的实例集合,H为X上定义的布尔假设的集合。另c:X->{0,1}为X上定义的任一个目标概念,并令D为任一训练样例的集合{<x,c(x)>}。对所有的X,H,c,D以及良好定义的S和G:

       

4.候选消除学习算法

 将G集合初始化为H中极大一般假设

将S集合初始化为H中极大特殊假设

对每个训练例d,进行以下操作:

  • 如果d是一正例

      • 从G中移去所有与d不一致的假设

      • 对S中每个与d不一致的假设s

             •从S中移去s

      • 把s的所有的极小一般化式h加入到S中,其中h满足

             •h与d一致,而且G的某个成员比h更一般

      • 从S中移去所有这样的假设:它比S中另一假设更一般

  • 如果d是一个反例

      • 从S中移去所有d不一致的假设

      • 对G中每个与d不一致的假设g

             •从G中移去g

             •把g的所有的极小特殊化式h加入到G中,其中h满足

                   •h与d一致,而且S的某个成员比h更特殊

             •从G中移去所有这样的假设:它比G中另一假设更特殊

5.算法举例

候选消除算法步骤(EnjoySport)

 

训练样例:

1.<Sunny,Warm,Normal,Strong,Warm,Same>,EnjoySport=Yes

2.<Sunny,Warm,High,Strong,Warm,Same>,EnjoySport=Yes

S0和G0为最初的边界集合,分别对应最特殊和最一般假设。训练样例1和2使得S边界变得更一般,如FIND-S算法中一样,这些样例对G边界没有影响。

训练样例:

3.<Rainy,Cold,High,Strong,Warm,Change>,EnjoySport=No

样例3是一个反例,他把G2边界特殊化为G3。注意在G3中有多个可选的极大一般假设。

训练样例:

4.<Sunny,Warm,High,Storage,Cool,Change>,EnjoySport=Yes

正例是S边界更一般,从S3变为S4。G3的一个成员也必须被删除,因为它不再比S4更一般。

 

EnjoySprot概念学习问题中的最终的变型空间

#include<iostream>
#include<string>
#include<vector>
#include<set>
 
using namespace std;
string TestState[4][7]={{"Sunny","Warm","Normal","Strong","Warm","Same","Yes"},{"Sunny","Warm","High","Strong","Warm","Same","Yes"},//测试数据1
	{"Rainy","Cold","High","Strong","Warm","Change","No"},{"Sunny","Warm","High","Strong","Cool","Change","Yes"}};
string TestState2[4][7]={{"Sunny","Warm","High","Strong","Warm","Same","Yes"},{"Sunny","Warm","Normal","Strong","Warm","Same","No"},//测试数据2
	{"Rainy","Cold","High","Strong","Warm","Change","No"},{"Sunny","Warm","High","Strong","Cool","Change","Yes"}};
 
 
 
class Candidate
{
private:
	int TestNum,AttributeNum;
	vector<string> S;
	set<vector<string>>G;
	vector<vector<string>>TestInstance;
public:
	Candidate(int Test,int Attribute,string test[][7])
	{
		TestNum=Test;
		AttributeNum=Attribute;
		vector<string> G0;
		for(int i=0;i<Attribute-1;i++)
		{
			S.push_back("0");
			G0.push_back("?");
		}
		G.insert(G0);
		TestInstance=vector<vector<string>>(Test,vector<string>(Attribute));
		for(int i=0;i<Test;i++)
		{
			for(int j=0;j<Attribute;j++)
			{
				TestInstance[i][j]=test[i][j];
			}
		}
	}
	void CandidateAlgriothm()
	{
		int i,j;
		for(i=0;i<TestNum;i++)
		{
			if(TestInstance[i][AttributeNum-1].compare("Yes")==0)
			{
				for(j=0;j<AttributeNum-1;j++)
				{
					if(S[j]=="0")S[j]=TestInstance[i][j];
					if(S[j].compare(TestInstance[i][j]))
					{
						S[j]="?";
					}
				}
				set<vector<string>>::iterator it;
				
				for(it=G.begin();it!=G.end();it++)
				{
					for(j=0;j<AttributeNum-1;j++)
					{
						if(S[j]=="?"&&(*it)[j]!=S[j])
						{
							G.erase(it);
							it=G.begin();
						}
					}
				}
			
			}
			else
			{
				set<vector<string>>::iterator it;
	
				for(it=G.begin();it!=G.end();)
				{
					vector<string> temp;
					for(j=0;j<AttributeNum-1;j++)
					{
						temp.push_back((*it)[j]);
					}
					if(IsRight(temp,TestInstance[i]))
					{
						for(j=0;j<AttributeNum-1;j++)
						{
							if(S[j]!="?"&&S[j]!=TestInstance[i][j]&&temp[j]=="?")
							{
								temp[j]=S[j];
								G.insert(G.begin(),temp);
								temp[j]="?";
							}
						}
						G.erase(it);
						it=G.begin();
					}
					else it++;
					temp.clear();
				}
			}
		
		}
 
	}
	bool IsRight(vector<string> a,vector<string> b)
	{
		for(int i=0;i<AttributeNum-1;i++)
		{
			if(a[i]!="?"&&a[i]!=b[i])return false;
		}
		return true;
	}
	void Show()
	{
		/*for(int i=0;i<TestNum;i++)
		{
			for(int j=0;j<AttributeNum;j++)
			{
				cout<<TestInstance[i][j]<<' ';
			}
			
		}*/
		cout<<"S:"<<endl;
		for(int i=0;i<AttributeNum-1;i++)
		{
			cout<<S[i]<<' ';
		}
		cout<<endl;
		set<vector<string>>::iterator it,temp; 
		cout<<"G:"<<endl;
        for(it=G.begin();it!=G.end();it++) 
		{
			temp=it;
			for(int j=0;j<AttributeNum-1;j++)
			{
				cout<<(*it)[j]<<' ';
			}
			if(!(++temp==G.end()))
			{
				cout<<',';
				
			}
			
		}
		cout<<endl;
	}
 
};
int main()
{
	Candidate Candi(4,7,TestState);
	
	Candi.CandidateAlgriothm();
	Candi.Show();
	Candidate Candi2(4,7,TestState2);
	Candi2.CandidateAlgriothm();
	Candi2.Show();
	system("pause");
	return 0;
}