五子棋智能算法——决策树数据处理(二)

  其实博弈树与决策树本质上是相同的 只是决策树追求的是信息嫡的下降 使可能性趋于一个最大值从而达到预测效果 而博弈树正如上篇博文所述追求的是选择从自身打分最高的一步棋 

要是看懂了上篇文章的博弈树(https://blog.csdn.net/viafcccy/article/details/90648852)的思想这里决策树也就不难了 作为AI的入门算法决策树是异常重要的 这里我决定先去实现决策树 再进一步实现MFC五子棋博弈树算法 因为决策树这里使用一个经典的例子 数据集较为简单 不像五子棋数据较为复杂无法直接明白算法的内容 而是被冗杂的数据缠身 

下面我们需要知道信息嫡是什么? 

很简单就是我说明天太阳从东边出来 这个是小概率事件 也就是不可能 我们把这种事情称之为信息嫡很低的事情

但是我说明天我要去打篮球这个不确定的因素就很多了 要考虑天气 上课等等因素 这种事情叫做信息嫡很高

所以今天完成这样一个例子 输入一些天气建立决策树来预测明天我能不能去打篮球

具体看这篇博文 https://blog.csdn.net/viafcccy/article/details/88695908

其实怎样度量前人已经推导出来

//计算以2为底的对数

double Log2(double x)

{

if(x<=0)

return 0.0;

else

return (double)log10(x)/log10(2);

}

//计算信息嫡

double I(double p1,double p2)

{

return -(p1*Log2(p1)+p2*Log2(p2));

}

代码实现也很简单

这样想一下上次的五子棋博弈树算法 这个就相当于我打分的函数

接下来看到信息嫡的公式我么需要统计数据算出权值 来计算信息嫡

//训练数据集结构

struct TRAINING

{

int outLook;

int temperature;

int humidity;

int windy;

int play;

struct TRAINING *next;

};

struct TRAINING trainingSet[TRAINING_NUMBER]=

{

{SUNNY   ,85,85,FALSE,NOT_PLAY,NULL},

{SUNNY   ,80,90,TRUE ,NOT_PLAY,NULL},

{VOERCAST,83,78,FALSE,CAN_PLAY,NULL},

{RAIN    ,70,96,FALSE,CAN_PLAY,NULL},

{RAIN    ,68,80,FALSE,CAN_PLAY,NULL},

{RAIN    ,65,70,TRUE ,NOT_PLAY,NULL},

{VOERCAST,64,65,TRUE ,CAN_PLAY,NULL},

{SUNNY   ,72,95,FALSE,NOT_PLAY,NULL},

{SUNNY   ,69,70,FALSE,CAN_PLAY,NULL},

{RAIN    ,75,80,FALSE,CAN_PLAY,NULL},

{SUNNY   ,75,70,TRUE ,CAN_PLAY,NULL},

{VOERCAST,72,90,TRUE ,CAN_PLAY,NULL},

{VOERCAST,81,75,FALSE,CAN_PLAY,NULL},

{RAIN    ,71,80,TRUE ,NOT_PLAY,NULL}

};

我使用代码将这些数据使用链表储存来便于我们的操作 


struct TRAINING *CreateTrainingLink(struct TRAINING set[])

{

struct TRAINING *head,*p,*q;

int i;

p=(struct TRAINING *)malloc(sizeof(struct TRAINING));

memset(p,0,sizeof(struct TRAINING));

head=p;

p->next=NULL;

q=p;

for(i=0;i<TRAINING_NUMBER;i++)

{

p=(struct TRAINING *)malloc(sizeof(struct TRAINING));

memset(p,0,sizeof(struct TRAINING));

p->outLook=set[i].outLook;

p->temperature=set[i].temperature;

p->humidity=set[i].humidity;

p->windy=set[i].windy;

p->play=set[i].play;

p->next=NULL;

q->next=p;

q=q->next;

}

return head;

}

计算加权平均值 用于计算信息嫡

//计算加权平均值

double InformationAttr(int attribute,struct TRAINING *head)

{

struct TRAINING *p;

struct TEMPER_HUMID_GAIN tGain[3];

struct TEMPER_HUMID_GAIN mGain[2];

int c=0;

int i=0,j=0;

int sunny=0,overcast=0,rain=0;

int sPlay=0,oPlay=0,rPlay=0;

int wind=0,windPlay=0;

int noWind=0,noWindPlay=0;

double p1=0,p2=0,p3=0;

double i1=0,i2=0,i3=0;

p=head->next;

switch(attribute)

{

case OUTLOOK:

while(p)

{

c++;

if(p->outLook==SUNNY)

{

sunny++;//晴天总数

if(p->play==CAN_PLAY)

sPlay++;//是晴天时且可以打球的天数

}

if(p->outLook==VOERCAST)

{

overcast++;

if(p->play==CAN_PLAY)

oPlay++;

}

if(p->outLook==RAIN)

{

rain++;

if(p->play==CAN_PLAY)

rPlay++;

}

p=p->next;

}

p1=(double)sunny/c;

p2=(double)overcast/c;

p3=(double)rain/c;

if(sunny)

i1=I((double)sPlay/sunny,

(double)(sunny-sPlay)/sunny);

if(overcast)

i2=I((double)oPlay/overcast,

(double)(overcast-oPlay)/overcast);

if(rain)

i3=I((double)rPlay/rain,

(double)(rain-rPlay)/rain);

return p1*i1+p2*i2+p3*i3;

case TEMPERATURE:

for(i=0;i<3;i++)

{

tGain[i].c=0;

tGain[i].playCount=0;

if(i==0)

tGain[i].value=HIGH_TEMPERATURE;

else if(i==1)

tGain[i].value=MID_TEMPERATURE;

else

tGain[i].value=COLD_TEMPERATURE;

}

while(p)

{

c++;

if(p->temperature/10==HIGH_TEMPERATURE)

{

tGain[0].c++;

if(p->play==CAN_PLAY)

tGain[0].playCount++;

}

else if(p->temperature/10==MID_TEMPERATURE)

{

tGain[1].c++;

if(p->play==CAN_PLAY)

tGain[1].playCount++;

}

else if(p->temperature/10==COLD_TEMPERATURE)

{

tGain[2].c++;

if(p->play==CAN_PLAY)

tGain[2].playCount++;

}

p=p->next;

}

p1=(double)tGain[0].c/c;

p2=(double)tGain[1].c/c;

p3=(double)tGain[2].c/c;

if(tGain[0].c)

i1=I((double)tGain[0].playCount/tGain[0].c,

(double)(tGain[0].c-tGain[0].playCount)/tGain[0].c);

if(tGain[1].c)

i2=I((double)tGain[1].playCount/tGain[1].c,

(double)(tGain[1].c-tGain[1].playCount)/tGain[1].c);

if(tGain[2].c)

i3=I((double)tGain[2].playCount/tGain[2].c,

(double)(tGain[2].c-tGain[2].playCount)/tGain[2].c);

return p1*i1+p2*i2+p3*i3;

case HUMIDITY:

for(i=0;i<2;i++)

{

mGain[i].c=0;

mGain[i].playCount=0;

if(i==0)

mGain[i].value=HIGH_HUMIDITY;

else

mGain[i].value=NORMAL_HUMIDITY;

}

while(p)

{

c++;

if(p->humidity>=mGain[0].value)

{

mGain[0].c++;

if(p->play==CAN_PLAY)

mGain[0].playCount++;

}

else if(p->humidity<mGain[1].value)

{

mGain[1].c++;

if(p->play==CAN_PLAY)

mGain[1].playCount++;

}

p=p->next;

}

p1=(double)mGain[0].c/c;

p2=(double)mGain[1].c/c;

if(mGain[0].c)

i1=I((double)mGain[0].playCount/mGain[0].c,

(double)(mGain[0].c-mGain[0].playCount)/mGain[0].c);

if(mGain[1].c)

i2=I((double)mGain[1].playCount/mGain[1].c,

(double)(mGain[1].c-mGain[1].playCount)/mGain[1].c);

return p1*i1+p2*i2;

case WINDY:

while(p)

{

c++;

if(p->windy==TRUE)

{

wind++;

if(p->play==CAN_PLAY)

windPlay++;

}

if(p->windy==FALSE)

{

noWind++;

if(p->play==CAN_PLAY)

noWindPlay++;

}

p=p->next;

}

p1=(double)wind/c;

p2=(double)noWind/c;

if(wind)

i1=I((double)windPlay/wind,

(double)(wind-windPlay)/wind);

if(noWind)

i2=I((double)noWindPlay/noWind,

(double)(noWind-noWindPlay)/noWind);

return p1*i1+p2*i2;

}

return 0.0;

}

 

接下来继续 这里我们继续引入一个概念信息增量 info gain

公式是这个

为了便于理解,我们还是以一个实际的例子来说明信息增益的概念。假设有下表样本

第一列为QQ,第二列为性别,第三列为活跃度,最后一列用户是否流失。我们要解决一个问题:性别和活跃度两个特征,哪个对用户流失影响更大?我们通过计算信息熵可以解决这个问题。

按照分组统计,我们可以得到如下信息:

其中Positive为正样本(已流失),Negative为负样本(未流失),下面的数值为不同划分下对应的人数。那么可得到三个熵:

整体熵:

性别熵:

性别信息增益:

同理计算活跃度熵:

活跃度信息增益:

活跃度的信息增益比性别的信息增益大,也就是说,活跃度对用户流失的影响比性别大。在做特征选择或者数据分析的时候,我们应该重点考察活跃度这个指标。

上面案例可以一目了然的看出信息增益偏向于选择取值较多的特征,但根据熵的公式可知,特征越多,熵越大,所以除A特征的熵正好抵消了特征变量的复杂程度,避免了过拟合的存在。

好了get了这个两个东西 下面我们来实现计算gain 

 

double Gain(int attribute,struct TRAINING *head)

{

return Information(head)-InformationAttr(attribute,head);

}

到这里我们使用c语言完成了对于建立决策树数据的基本处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值