/*先把标题给写了、这样就能经常提醒自己*/
题记:今天下午去上厕所的一会儿时间,就把第四章给扫完了,说是扫完了主要是因为没有深入去看,对于某些证明都直接跳过了,看了一下里面的例子,大概懂个意思就行了
1. 朴素贝叶斯法
设输入空间 为 维向量的集合,输出空间为类标记集合 ,输入特征向量 ,输出类标记为 , 是 和 的联合概率分布,数据集
由 独立同分布产生。
朴素贝叶斯法就是通过训练集来学习联合概率分布 .具体怎么学习呢? 主要就是从先验概率分布和条件概率分布入手,俩个概率相乘即可得联合概率。
为什么称之为朴素呢,主要是其将条件概率的估计简化了,对条件概率分布作了条件独立性假设,这也是朴素贝叶斯法的基石,具体的假设如下
此公式在假设条件之下可以等价于
现在, 对于给定的输入向量 ,通过学习到的模型计算后验概率分布P(Y=Ck|X=x),后验分布中最大的类作为的输出结果,根据贝叶斯定理可知后验概率为
上面的公式可能有点歧义,分母的Ck应该写成Cj才对,因为P(X=x)=E P(Y=Cj)*P(X=x|Y=Cj)
而 对于所有 都是相同的,即此可以将输出结果简化为
至此大概讲解了朴素贝叶斯的基本方法步骤了,关于参数估计还有具体实例下次再写了。夏天真热啊!
2. 参数估计
2.1 极大似然估计
上一小节讲了对于给定的输入向量 ,其输出结果可表示为
对此可应用极大似然估计法来估计相应的概率,如先验概率 的极大似然估计是
设第个 特征 可能取值的集合为 ,条件概率 的极大似然估计是
公式看起来可能有点不实在,还是直接上例子来说明吧!
例子:试由下表的训练数据学习一个朴素贝叶斯分类器并确定 的类标记,表中 为特征, 为类标记。
据此可算出 是 后验分布中值 最大的,也就是最终的类标记为-1
2.2 贝叶斯 估计
极大似然估计的一个可能是会出现所要估计的概率值为 0的情况,这时会影响到后验概率的计算结果,解决这一问题的方法是采用贝叶斯估计,具体的只需要在极大似然估计的基础上加多一个参数即可。懒得继续写公式了,不想写了,刚刚码完代码!!
有兴趣的可以看一下具体的代码实现
package org.juefan.bayes; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.juefan.basic.FileIO; /** * 这是一个简易的贝叶斯分类器 * 只适用于离散数据,连续型数据的暂时请先绕道了^.^ * @author JueFan */ public class NaiveBayes{ // 平滑指数, 默认为拉普拉斯平滑,极大似然估计则为0 private static double Lambda = 1 ; // 存储先验概率数据 private Map<Object, Double> PriorProbability = new HashMap<> (); // 存储条件概率数据 private Map<Object, ArrayList<Map<Object, Double>>> ConditionProbability = new HashMap<> (); /** * 计算类别的先验概率 * @param datas */ public void setPriorPro(ArrayList<Data> datas){ int counts = datas.size(); for (Data data: datas){ if (PriorProbability.containsKey(data.y)){ PriorProbability.put(data.y, PriorProbability.get(data.y) + 1 ); } else { PriorProbability.put(data.y, ( double ) 1 ); } } for (Object o: PriorProbability.keySet()) PriorProbability.put(o, (PriorProbability.get(o) + Lambda)/(counts + Lambda * PriorProbability.size())); } /** * 计算条件概率 * @param datas */ public void setCondiPro(ArrayList<Data> datas){ Map <Object, ArrayList<Data>> tmMap = new HashMap<> (); // 按类别先将数据分类存放 for (Data data: datas){ if (tmMap.containsKey(data.y)){ tmMap.get(data.y).add(data); } else { ArrayList <Data> tmDatas = new ArrayList<> (); tmDatas.add(data); tmMap.put(data.y, tmDatas); } } // 条件概率主体 for (Object o: tmMap.keySet()){ ArrayList <Map<Object, Double>> tmCon = new ArrayList<> (); int LabelCount = tmMap.get(o).size(); // 计算每个特征的相对频数 for (Data data: tmMap.get(o)){ for ( int i = 0; i < data.x.size(); i++ ){ if (tmCon.size() < i + 1 ){ Map <Object, Double> tmMap2 = new HashMap<> (); tmMap2.put(data.x.get(i), ( double ) 1 ); tmCon.add(tmMap2); } else { if (tmCon.get(i).containsKey(data.x.get(i))){ tmCon.get(i).put(data.x.get(i), tmCon.get(i).get(data.x.get(i)) + 1 ); } else { tmCon.get(i).put(data.x.get(i), ( double ) 1 ); } } } } // 计算条件概率 for ( int i = 0; i < tmCon.size(); i++ ){ for (Object o1: tmCon.get(i).keySet()){ tmCon.get(i).put(o1, (tmCon.get(i).get(o1) + Lambda)/(LabelCount + Lambda * tmCon.get(i).size())); } } ConditionProbability.put(o, tmCon); } } /** * 判断实例的类别 * @param data * @return 判断结果 */ public Object getLabel(Data data){ Object label = new Object(); double pro = 0D; for (Object o: PriorProbability.keySet()){ double tmPro = 1 ; tmPro *= PriorProbability.get(o); for ( int i = 0; i < data.x.size(); i++ ){ tmPro *= ConditionProbability.get(o).get(i).get(data.x.get(i)); } if (tmPro > pro){ pro = tmPro; label = o; } System.out.println(o.toString() + " :的后验概率为: " + tmPro); } return label; } public static void main(String[] args) { ArrayList <Data> datas = new ArrayList<> (); FileIO fileIO = new FileIO(); fileIO.setFileName( ".//file//bayes.txt" ); fileIO.FileRead(); for (String data: fileIO.fileList){ datas.add( new Data(data)); } NaiveBayes bayes = new NaiveBayes(); bayes.setPriorPro(datas); bayes.setCondiPro(datas); Data data = new Data("1\t2\tS" ); System.out.println(data.toString() + "\t的判断类别为: " + bayes.getLabel(data)); } }
对代码有兴趣的可以上本人的GitHub查看: https://github.com/JueFan/StatisticsLearningMethod/