人工智能一种现代化的学习方法(第3版)学习笔记。
决策理论 = 概率理论 + 效用理论
决策理论基本思想:
一个Agent是理性的,当且仅当它选择能产生最高期望效用的行动,这里的期望效用是行动的所有可能结果的平均。这成为期望效用最大化(Maximum Expected Utility, MEU)。先验概率(无条件概率)
是指根据以往经验和分析得到的概率,如全概率公式,它往往作为”由因求果”问题中的”因”出现的概率·
后验概率(条件概率)
基于新的信息,修正原来的先验概率后所获得的更接近实际情况的概率估计。
随机变量
变量的名字以大写字母开头,比如投掷两个一样的骰子,他们的点数之和Total就是随机变量。Total的定义域是{2,…,12};一个布尔变量的定义域是{true,false}(变量的值总是小写)。
例:
“如果患者是一个没有牙痛的青少年,那么他有牙洞的概率是0.1” => P(cavity|?toothache^teen)=0.1
例:
三个布尔变量
- Toothache,牙痛
- Cavity,牙洞
- Catch,牙医的钢探针不洁导致牙龈感染
对应的完全联合分布2x2x2的表格:
(1)将使命题为真的概率相加
P(cavity∨toothache)=0.108+0.012+0.072+0.008+0.016+0.064=0.28(∨是逻辑或)
(2)无条件概率(边缘概率)
P(cavity)=0.108+0.012+0.072+0.008=0.2
计算,P(toothace,catch,cavity,cloudy)=P(cloudy|toothace,catch,cavity)P(toothace,catch,cavity)
因为cloudy与toothace,catch,cavity互相独立,
所以,P(cloudy|toothace,catch,cavity)=P(cloudy)
所以,P(toothace,catch,cavity,cloudy)=P(cloudy) P(toothace,catch,cavity)
常用形式:
通用形式:
例:
医生知道脑膜炎会引起病人脖子僵硬,比如有70%的机会。医生还了解一些无条件事实:病人患脑膜炎的先验概率是1/50000,而任何一个脖子僵硬的先验概率为1%,令s表示“病人脖子僵硬”的命题,m表示“病人患有脑膜炎”的命题,则有
也就是说,我们期望700个有脖子僵硬症状的病人中只有不到1个人患有脑膜炎。注意,尽管脑膜炎相当强烈地预示着会有脖子僵硬的症状(概率为0.7),但脖子僵硬的病人患有脑膜炎的 概率依然很低。这是因为脖子僵硬的先验概率大大高于患脑膜炎的先验概率。
朴素贝叶斯:
参考算法杂货铺——分类算法之朴素贝叶斯分类(Naive Bayesian classification)
例:
实验内容:
利用贝叶斯算法或者决策树算法进行数据分类操作
数据集:汽车评估数据集(见附录CarDatas.txt)
实验步骤:
1.仔细阅读并了解实验数据集;
2.使用任何一种熟悉的计算机语言(比如C,Java或者matlab)实现朴素贝叶斯算法或者决策树算法;
3.利用朴素贝叶斯算法或者决策树算法在训练数据上学习分类器,训练数据的大小分别设置为:前100个数据,前200个数据,前500个数据,前700个数据,前1000个数据,前1350个数据;
4.利用测试数据对学习的分类器进行性能评估;
5.统计分析实验结果并上交实验报告;
实验思路:
#include
#include
#include
#include
#include
#include
using namespace std;
int countTrain = 0;//训练样本数目
int countTest = 0;//测试样本数目
int countTestSuc = 0;//测试样本正确的数目
int countF=100; //训练和测试的分界
string CVname[4]={"unacc","acc","good","vgood"};
int ClassValues[4]; //unacc, acc, good, vgood
int buying[4][4]; //vhigh, high, med, low.
int maint[4][4]; // vhigh, high, med, low.
int doors[4][4]; //2, 3, 4, 5more.
int persons[4][4]; //2, 4, more.
int lug_boot[4][4]; //small, med, big.
int safety[4][4]; //low, med, high.
float ClassValuesL[4]; //unacc, acc, good, vgood
float buyingL[4][4]; //vhigh, high, med, low.
float maintL[4][4]; // vhigh, high, med, low.
float doorsL[4][4]; //2, 3, 4, 5more.
float personsL[4][4]; //2, 4, more.
float lug_bootL[4][4]; //small, med, big.
float safetyL[4][4]; //low, med, high.
//统计个数
void Tonji(string a,string b,string c,string d,string e,string f,string g){
//cout<
for(int i=0;i<4;i++)
if(g==CVname[i]){
ClassValues[i]++;
//buying: vhigh, high, med, low.
if(a=="vhigh") buying[0][i]++;
else if(a=="high") buying[1][i]++;
else if(a=="med") buying[2][i]++;
else if(a=="low") buying[3][i]++;
//maint: vhigh, high, med, low.
if(b=="vhigh") maint[0][i]++;
else if(b=="high") maint[1][i]++;
else if(b=="med") maint[2][i]++;
else if(b=="low") maint[3][i]++;
//doors: 2, 3, 4, 5more.
if(c=="2") doors[0][i]++;
else if(c=="3") doors[1][i]++;
else if(c=="4") doors[2][i]++;
else doors[3][i]++;
//persons: 2, 4, more.
if(d=="2") persons[0][i]++;
else if(d=="4") persons[1][i]++;
else persons[2][i]++;
//lug_boot: small, med, big.
if(e=="small") lug_boot[0][i]++;
else if(e=="med") lug_boot[1][i]++;
else if(e=="big") lug_boot[2][i]++;
//safety: low, med, high.
if(f=="low") safety[0][i]++;
else if(f=="med") safety[1][i]++;
else if(f=="high") safety[2][i]++;
break;
}
}
//读取文件
void ReadFileTrain(){
ifstream fin("CarDatas.txt");
string a,b,c,d,e,f,g;
int i = countF;
while((i--)>0 && fin>>a && fin>>b&& fin>>c && fin>>d && fin>>e && fin>>f && fin>>g){
countTrain++;
Tonji(a,b,c,d,e,f,g);
}
fin.close();
cout<<"训练样本countTrain="<//统计得到在各类别下各个特征属性的条件概率估计
void CalAP(){ //概率P(yi)
for(int i=0;i<4;i++){
ClassValuesL[i] = (float) ClassValues[i]/countTrain;
}
//特别注意的是P(ai|yi)=ai/0的情况!!!,会使 P(ai|yi)等于nan;
for(int i=0;i<4;i++){ //概率P(ai|yi)
for(int j=0;j<4;j++){
buyingL[i][j] = (float) buying[i][j]/ClassValues[j]; if(buyingL[i][j]<0 || buyingL[i][j]>1) buyingL[i][j]=0;
maintL[i][j] = (float) maint[i][j]/ClassValues[j]; if(maintL[i][j]<0 || maintL[i][j]>1) maintL[i][j]=0;
doorsL[i][j] = (float) doors[i][j]/ClassValues[j]; if(doorsL[i][j]<0 || doorsL[i][j]>1) doorsL[i][j]=0;
}
}
for(int i=0;i<3;i++){ //概率P(ai|yi)
for(int j=0;j<4;j++){
personsL[i][j] = (float) persons[i][j]/ClassValues[j]; if(personsL[i][j]<0 || personsL[i][j]>1) personsL[i][j]=0;
lug_bootL[i][j] = (float) lug_boot[i][j]/ClassValues[j]; if(lug_bootL[i][j]<0 || lug_bootL[i][j]>1) lug_bootL[i][j]=0;
safetyL[i][j] = (float) safety[i][j]/ClassValues[j]; if(safetyL[i][j]<0 || safetyL[i][j]>1) safetyL[i][j]=0;
}
}
}
//一行数据的准确与否,P(Bi|A)=P(A|Bi)P(Bi)/P(A),其中P(A)相同,只需比较分子的大小即可
bool TestLine(string ai,string bi,string ci,string di,string ei,string fi,string gi){
int b, m, d, p, l, s;
//buying:
if(ai=="vhigh") b=0;
else if(ai=="high") b=1;
else if(ai=="med") b=2;
else if(ai=="low") b=3;
//maint:
if(bi=="vhigh") m=0;
else if(bi=="high") m=1;
else if(bi=="med") m=2;
else if(bi=="low") m=3;
//doors:
if(ci=="2") d=0;
else if(ci=="3") d=1;
else if(ci=="4") d=2;
else d=3;
//persons:
if(di=="2") p=0;
else if(di=="4") p=1;
else p=2;
//lug_boot:
if(ei=="small") l=0;
else if(ei=="med") l=1;
else if(ei=="big") l=2;
//safety:
if(fi=="low") s=0;
else if(fi=="med") s=1;
else if(fi=="high") s=2;
float Bi;
float MaxB=0;
int t=0;
//计算四个P(Bi|A)的概率取最大的
for(int i=0;i<4;i++){
Bi=buyingL[b][i] * maintL[m][i] * doorsL[d][i] * personsL[p][i] * lug_bootL[l][i] * safetyL[s][i] * ClassValuesL[i];
if(MaxB < Bi && Bi<=1){
MaxB = Bi;
t = i;
}
}
//判断预测和事实是否相等
if(CVname[t]==gi) return true;
else return false;
}
//读取并测试文件
void ReadFileTest(){
ifstream fin("CarDatas.txt");
string a,b,c,d,e,f,g;
bool t=false;
int i=0;
while(++i && fin>>a && fin>>b&& fin>>c && fin>>d && fin>>e && fin>>f && fin>>g){
if(i>countF){
countTest++;
t=TestLine(a,b,c,d,e,f,g);
if(t) countTestSuc++;
}
}
fin.close();
}
void setZero();
int main(){
int a[5]={100,200,500,700,1350};
for(int i=0;i<5;i++){
setZero();
countF=a[i]; //训练和测试的分界
ReadFileTrain(); //读取文件并且统计个数
CalAP(); //计算条件概率
ReadFileTest(); //测试样本
cout<<"预测正确countTestSuc="<cout<<"测试样本countTest="<cout<<"准确率为:"<<100.0*((float)countTestSuc/(float)countTest)<<"%"<return 0;
}
//重新赋值为零
void setZero(){
countTrain = 0;//训练样本数目
countTest = 0;//测试样本数目
countTestSuc = 0;//测试样本正确的数目
for(int i=0;i<4;i++)
for(int j=0;j<4;j++){
ClassValues[i]=0; //unacc, acc, good, vgood
buying[i][j]=0; //vhigh, high, med, low.
maint[i][j]=0; // vhigh, high, med, low.
doors[i][j]=0; //2, 3, 4, 5more.
persons[i][j]=0; //2, 4, more.
lug_boot[i][j]=0; //small, med, big.
safety[i][j]=0; //low, med, high.
ClassValuesL[i]=0; //unacc, acc, good, vgood
buyingL[i][j]=0; //vhigh, high, med, low.
maintL[i][j]=0; // vhigh, high, med, low.
doorsL[i][j]=0; //2, 3, 4, 5more.
personsL[i][j]=0; //2, 4, more.
lug_bootL[i][j]=0; //small, med, big.
safetyL[i][j]=0; //low, med, high.
}
}