您的位置:首页 > 其它

朴素贝叶斯在文本分类中的应用之 伯努利

2016-03-21 00:00 387 查看
摘要: 转的http://yzmduncan.iteye.com/blog/1930695 代码没测试

贝叶斯定理:
对于随机事件A和B:A发生的概率为P(A),B发生的概率为P(B),在B发生的情况下,A发生的概率为P(A|B)。A和B一起发生的联合概率为P(AB)。有:P(A|B) X P(B) = P(AB) = P(B|A) X P(A),则有:
P(A|B) = P(B|A)P(A) / P(B)
文本分类(Text Categorization)是指计算机将一片文档归于预先给定的某一类或几类的过程。文本分类的特征提取过程是分词。目前比较好的中文分词器有中科院的ictclas,庖丁,IK等等。经过分词后,每个词就是一个特征。分词中可以自己配置停用词库,扩展词库等。特征选择有诸如TF-IDF,CHI等特征选择算法,就不在此赘述。
朴素贝叶斯计算先验概率P(C)和条件概率P(X|C)的方法有两种:多项式模型伯努利模型。两者在计算的时候有两点差别:多项式会统计词频,而伯努利认为单词出现就记为1,没出现记为0,可以看到一个是基于词频,一个是基于文档频率;伯努利在分类时,将词库中的没有出现在待分类文本的词作为反方考虑
在计算条件概率时,当待分类文本中的某个词没有出现在词库中时,概率为0,会导致很严重的问题,需要考虑拉普拉斯平滑(laplace smoothing):它是将所有词出现的次数+1,再进行统计。



再一个问题就是概率太小而词数太多,会超double,用log将乘法转成加法

伯努利朴素贝叶斯算法伪代码如下:



伯努利朴素贝叶斯代码:

Java代码


/**

* @author zhongmin.yzm

* 语料训练并载入内存

* */

public class TrainingDataManager {

/** 特征索引 */

private Map<String, Integer> termIndex;

/** 类索引 */

private Map<String, Integer> classIndex;

/** 索引-类名 */

public List<String> className;

/**类的个数*/

private int numClasses = 0;

/**训练样本的所有特征(出现多次只算一个)*/

private int vocabulary = 0;

/**训练文本总数*/

private int DocsNum = 0;

/**属于某类的文档个数*/

private int[] classDocs;

/**类别c中包含属性 x的训练文本数量*/

private int[][] classKeyMap;

/** 标志位: 分类时的优化 */

private static boolean flag[];

private void buildIndex(List<List<String>> contents, List<String> labels) {

classIndex = new HashMap<String, Integer>();

termIndex = new HashMap<String, Integer>();

className = new ArrayList<String>();

Integer idTerm = new Integer(-1);

Integer idClass = new Integer(-1);

DocsNum = labels.size();

for (int i = 0; i < DocsNum; ++i) {

List<String> content = contents.get(i);

String label = labels.get(i);

if (!classIndex.containsKey(label)) {

idClass++;

classIndex.put(label, idClass);

className.add(label);

}

for (String term : content) {

if (!termIndex.containsKey(term)) {

idTerm++;

termIndex.put(term, idTerm);

}

}

}

vocabulary = termIndex.size();

numClasses = classIndex.size();

}

public void startTraining(List<List<String>> contents, List<String> labels) {

buildIndex(contents, labels);

//去重

List<List<Integer>> contentsIndex = new ArrayList<List<Integer>>();

for (int i = 0; i < DocsNum; ++i) {

List<Integer> contentIndex = new ArrayList<Integer>();

List<String> content = contents.get(i);

for (String str : content) {

Integer wordIndex = termIndex.get(str);

contentIndex.add(wordIndex);

}

Collections.sort(contentIndex);

int num = contentIndex.size();

List<Integer> tmp = new ArrayList<Integer>();

for (int j = 0; j < num; ++j) {

if (j == 0 || contentIndex.get(j - 1) != contentIndex.get(j)) {

tmp.add(contentIndex.get(j));

}

}

contentsIndex.add(tmp);

}

//

classDocs = new int[numClasses];

classKeyMap = new int[numClasses][vocabulary];

flag = new boolean[vocabulary];

for (int i = 0; i < DocsNum; ++i) {

List<Integer> content = contentsIndex.get(i);

String label = labels.get(i);

Integer labelIndex = classIndex.get(label);

classDocs[labelIndex]++;

for (Integer wordIndex : content) {

classKeyMap[labelIndex][wordIndex]++;

}

}

}

/** 分类 时间复杂度 O(c*v) */

public String classify(List<String> text) {

double maxPro = Double.NEGATIVE_INFINITY;

int resultIndex = 0;

//标记待分类文本中哪些特征 属于 特征表

for (int i = 0; i < vocabulary; ++i)

flag[i] = false;

for (String term : text) {

Integer wordIndex = termIndex.get(term);

if (wordIndex != null)

flag[wordIndex] = true;

}

//对特征集中的每个特征: 若出现在待分类文本中,直接计算;否则作为反方参与

for (int classIndex = 0; classIndex < numClasses; ++classIndex) {

double pro = Math.log10(getPreProbability(classIndex));

for (int wordIndex = 0; wordIndex < vocabulary; ++wordIndex) {

if (flag[wordIndex])

pro += Math.log10(getClassConditionalProbability(classIndex, wordIndex));

else

pro += Math.log10(1 - getClassConditionalProbability(classIndex, wordIndex));

}

if (maxPro < pro) {

maxPro = pro;

resultIndex = classIndex;

}

}

return className.get(resultIndex);

}

/** 先验概率: 类C包含的文档数/总文档数 */

private double getPreProbability(int classIndex) {

double ret = 0.0;

ret = 1.0 * classDocs[classIndex] / DocsNum;

return ret;

}

/** 条件概率: 类C中包含关键字t的文档个数/类C包含的文档数 */

private double getClassConditionalProbability(int classIndex, int termIndex) {

int NCX = classKeyMap[classIndex][termIndex];

int N = classDocs[classIndex];

double ret = (NCX + 1.0) / (N + DocsNum);

return ret;

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: