@decision P(yes) {0.6428571428571429}
@decision P(no) {0.35714285714285715}
@data
P(outlook=sunny|yes),0.2222222222222222
P(outlook=sunny|no),0.6
P(outlook=overcast|yes),0.4444444444444444
P(outlook=overcast|no),0.0
P(outlook=rainy|yes),0.3333333333333333
P(outlook=rainy|no),0.4
P(temperature=hot|yes),0.2222222222222222
P(temperature=hot|no),0.4
P(temperature=mild|yes),0.4444444444444444
P(temperature=mild|no),0.4
P(temperature=cool|yes),0.3333333333333333
P(temperature=cool|no),0.2
P(humidity=high|yes),0.3333333333333333
P(humidity=high|no),0.8
P(humidity=normal|yes),0.6666666666666666
P(humidity=normal|no),0.2
P(windy=TRUE|yes),0.3333333333333333
P(windy=TRUE|no),0.6
P(windy=FALSE|yes),0.6666666666666666
P(windy=FALSE|no),0.4
2.3
上面的各个概率计算过程如下:P(yes)=9/14 (在训练集中,yes出现9次,总数是14 )
P(no)=5/14
P(outlook=sunny|yes)=2/9(同时为sunny和yes的记录出现了2次,而yes总数出现了9次)
P(outlook=sunny|no)=3/5 (同时为sunny和no的记录出现了3次,no出现了5次)其它的计算一样,这里不例举了。
2.4 测试:
求 (sunny,hot,high,FALSE) 属于yes还是no呢?
为了显示好看,把(sunny,hot,high,FALSE) 用1来表示
计算方法如下:
属于yes的概率(其它这里严格意义的概率,因为没有除以分母)
P(1|yes)= P(yes)*P(sunny|yes)*P(hot|yes)*P(high|yes)*P(FALSE|yes)=0.6428571428571429*0.2222222222222222*0.2222222222222222*0.3333333333333333*0.6666666666666666=0.007(约等)
P(1|no)=0.027显然它属于no的概率大一点,判定它为no.
2.5 零频问题
以上计算没有考虑零频问题,实际的计算中应该避免零频问题,即在每个项计数时加1。
3.数学语言描述
关于数学公式的描述,这位大牛写得非常详细,建议大家看一看。
3.1贝叶斯定理:
3.2 推导
朴素贝叶斯分类的正式定义如下:
1、设
为一个待分类项,而每个a为x的一个特征属性。
2、有类别集合
。
3、计算
。
4、如果
,则
。
那么现在的关键就是如何计算第3步中的各个条件概率。我们可以这么做:
1、找到一个已知分类的待分类项集合,这个集合叫做训练样本集。
2、统计得到在各类别下各个特征属性的条件概率估计。即
。
3、如果各个特征属性是条件独立的,则根据贝叶斯定理有如下推导:
因为分母对于所有类别为常数,因为我们只要将分子最大化皆可。又因为各特征属性是条件独立的,所以有:
5.测试结果
下面结果对各项统计加1,为了避免零频问题。
sunny,hot,high,FALSE 判断的结果是:no --参考数值是:0.059
overcast,mild,high,TRUE 判断的结果是:yes --参考数值是:0.028
overcast,hot,normal,FALSE 判断的结果是:yes --参考数值是:0.052
rainy,mild,high,TRUE 判断的结果是:no --参考数值是:0.059在实际中应随机抽取80%数据作为样本集,20%作为测试集,本例没考虑这点。
4.JAVA实现
详细源码请到我的Github上下载:
时间匆忙,写例子为讲解。代码中各种漏洞请各位指出。谢谢!
以下仅给出训练部分的代码:
package sequence.machinelearning.naivebayes.bayesdemo;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.LinkedList;
/**
* 案例:http://www.cnblogs.com/zhangchaoyang/articles/2586402.html
* @author Jamas
* 也参考了这篇文章:http://www.cnblogs.com/leoo2sk/archive/2010/09/17/naive-bayesian-classifier.html
*/
public class Train {
public static LinkedList lisatt = new LinkedList(); // 存储属性的名称:outlook,temperature,humidity,windy
public static LinkedList> lisvals = new LinkedList>(); //outlook:sunny,overcast,rainy 存储每个属性的取值,属性的特征
public static LinkedList listdata = new LinkedList();; // 原始数据
public static final String patternString = "@attribute(.*)[{](.*?)[}]";
//存储分类,比如,是,否。再比如:检测SNS社区中不真实账号,是真实用户还是僵尸用户
public static LinkedList sort=new LinkedList();
//计算P(F1|C)P(F2|C)...P(Fn|C)P(C),并保存为文本文件
/**
* 为了避免零频问题,对每个计数加1,只要数量足够大,加1是可以忽略的
* @throws IOException
*/
public void CountProbility() throws IOException{
String src="datafile/naivebayes/train/out/trainresult.arff";
delfile(src);
File file=new File(src);
if(file.exists())
file.createNewFile();
FileOutputStream out=new FileOutputStream(file,true);
Map map=new HashMap();
//先计算判定结果的概率,保存为文件
for(int i=0;i
//第一个for对取出sort,第二个for对data中的sort进行计数
//避免零频问题,对各项计数加1
Integer sum=1;
String sortname=sort.get(i);
Double probability=0.0;
for(int j=0;j
String[] line=listdata.get(j);
if(line[line.length-1].equals(sortname)){
sum=sum+1;
}
}
map.put(sortname, sum);
probability=Double.valueOf(sum)/Double.valueOf(listdata.size());
//写入文件
StringBuffer sb=new StringBuffer();
sb.append("@decision P("+sortname+") {"+probability.toString()+"}\n");//如果不加"/n"则不能实现换行。
System.out.print(sb.toString());
out.write(sb.toString().getBytes("utf-8"));
}
out.write("@data\n".getBytes("utf-8"));
System.out.print("@data\n");
//先计算判定结果的概率,保存为文件
//out.close(); //到最后写完的时候再关闭
//分别统计P(F1|C)P(F2|C)...P(Fn|C)的个数,参考:http://www.ruanyifeng.com/blog/2013/12/naive_bayes_classifier.html
//对属性进行循环
for(int i=0;i
String attname=lisatt.get(i);
List lisval=lisvals.get(i);
//对属性的特征进行循环
for(int j=0;j
String attval=lisval.get(j);
//先取出sort(yes 还是no情况)
for(int n=0;n
//避免零频问题,对各项计数加1
Integer sum=1;
String sortname=sort.get(n);
Double probability=0.0;
//取出数据集进行for
for(int k=0;k
String[] line=listdata.get(k);
if(line[line.length-1].equals(sortname)&&line[i].equals(attval)){
sum=sum+1;
}
}
probability=Double.valueOf(sum)/Double.valueOf(map.get(sortname));
//写入文件
StringBuffer sb=new StringBuffer();
sb.append("P("+attname+"="+attval+"|"+sortname+"),"+probability+"\n");//如果不加"/n"则不能实现换行。
System.out.print(sb.toString());
out.write(sb.toString().getBytes("utf-8"));
}
}
}
out.close();
}
//读取arff文件,给attribute、attributevalue、data赋值
public void readARFF(File file) {
try {
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
String line;
Pattern pattern = Pattern.compile(patternString);
while ((line = br.readLine()) != null) {
if (line.startsWith("@decision")) {
line = br.readLine();
if(line=="")
continue;
String[] type = line.split(",");
for(int i=0;i
sort.add(type[i].trim());
}
}
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
lisatt.add(matcher.group(1).trim());
String[] values = matcher.group(2).split(",");
ArrayList al = new ArrayList(values.length);
for (String value : values) {
al.add(value.trim());
}
lisvals.add(al);
} else if (line.startsWith("@data")) {
while ((line = br.readLine()) != null) {
if(line=="")
continue;
String[] row = line.split(",");
listdata.add(row);
}
} else {
continue;
}
}
br.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
Train train=new Train();
train.readARFF(new File("datafile/naivebayes/train/in/weather.nominal.arff"));
train.CountProbility();
}
public void delfile(String filepath){
File file=new File(filepath);
if(file.exists())
{
//file.createNewFile();
file.delete();
}
}
}