原创作品,出自 “晓风残月xj” 博客,欢迎转载,转载时请务必注明出处(http://blog.csdn.net/xiaofengcanyuexj)。

由于各种原因,可能存在诸多不足,欢迎斧正!

  最近在想怎么利用数据挖掘的方法进行评论自动审核,分类为垃圾评论和非垃圾评论,完成自动审核功能。实现中文文本分类,支持文件、文本分类,基于多项式分布的朴素贝叶斯分类器。由于工作实际应用是二分类,加之考虑到每个分类属性都建立map存储词语向量可能引起的内存问题,所以目前只支持二分类。当然,直接复用这个结构扩展到多分类也是很容易。之所以自己写,主要原因是没有仔细研读mahout、weka等代码,不能灵活地进行中文分词、停用词过滤、词频统计、TF-IDF等,也就是向量化和特征提取没有自己手写相对灵活。

一、贝叶斯分类器

  贝叶斯分类器是基于先验概率与条件概率进行概率计算的分类器。X是特征属性,Y是分类属性,P(Y|{x0,x1....xn})是X在取值{x0,x1,...xn}的条件下Y发生的概率,成为P(Y)的后验概率,P(Y)的先验概率。实际在计算P(Y|{x0,x1....xn})的时候由于维度太高,至少需要考虑特征属性与分类属性的所有搭配情况,计算量大而且无法对待分类数据集进行全面覆盖。

1.1朴素贝叶斯

  朴素贝叶斯就是假设特征属性的取值彼此独立,即没有相互作用关系。如果P(AB|C)=P(A|C)P(B|C),则A和B在C条件独立。贝叶斯定理也是贝叶斯基于先验概率计算条件概率的重要理论基础,如下是贝叶斯定理:

       

待分类的特征属性      


类别属性 


1)、在有分类属性的数据集上,计算:


2)、在给定特征属性数据上,有贝叶斯定理:

3)、已知P(x)是常数,加之特征属性间条件独立,只需求
 

二、中文文本分类

  中文分本分类通用方法是将文本按照一定规则编码成向量形式:特征属性和分类属性。具体的是利用一定的分词规则将文本切成一个个单词,然后去除停用词,如“了”、“的”等 没有实际语义含义的词汇,接着可以从剩余的词中选出尽可能标识分类属性的词汇降低维度,选取出来的词语组成特征属性。可以假设不同词汇的出现是相对独立的,于是就转换成了标准的朴素贝叶斯分类模型。

2.1.分词

 下面是知乎上一段关于中文分词理论上说明,觉得通俗有用,在此摘抄,标识感谢。原贴。中文分词算法大概分为两大类

 1)、第一类是基于字符串匹配,即扫描字符串,如果发现字符串的子串和词相同,就算匹配。

这类分词通常会加入一些启发式规则,比如“正向/反向最大匹配”, “长词优先” 等策略。这类算法优点是速度块,都是O(n)时间复杂度,实现简单,效果尚可。也有缺点,就是对歧义和未登录词处理不好。歧义的例子很简单"长春市/长春/药店" "长春/市长/春药/店".未登录词即词典中没有出现的词,当然也就处理不好。ikanalyzer,paoding 等就是基于字符串匹配的分词。

2)、第二类是基于统计以及机器学习的分词方式
这类分词基于人工标注的词性和统计特征,对中文进行建模,即根据观测到的数据(标注好的语料)对模型参数进行估计,即训练。 在分词阶段再通过模型计算各种分词出现的概率,将概率最大的分词结果作为最终结果。常见的序列标注模型有HMM和CRF。这类分词算法能很好处理歧义和未登录词问题,效果比前一类效果好,但是需要大量的人工标注数据,以及较慢的分词速度。ICTCLAS是基于HMM的分词库。

2.2.去停用词

 英文是以词为单位的,词和词之间是靠空格隔开,而中文是以字为单位,字连起来组成词语。为了降低时空复杂度,提高存储和计算效率,会自动忽略某些词,即为停用词。停用词包括过滤词,如特定时期的黄色、政治等敏感关键词。停用词主要有两类:
   1)、过于频繁的词语,包括"然而"、"下面"等等。
   2)、文本中出现频率很高,但没有语义含义的词,包括副词、介词、连词等等。

关于停用词,可以结合具体的数据集进行设定,如电商的禁用词等等。很多通用的停用词集合,这个个人认为还不错,可用停用词集合

2.3.特征提取

  文本分词并出去停用词之后,剩下的都可以看作是有效的词语,可以初步作为提取出来的特征属性。但是,需要进行一下处理,可以给不同的词语设置不同的权重,比较通用的方法是TF-IDF算法。

  TF-IDF是采用统计思想,用以评估词语相对文件集中某个文件的重要程度。字词的重要性与它在文件中出现的次数成正比增加,但同时会与着它在语料库中出现的频率成反比下降,如下面的公式。

  

 本次实验由于使用朴素贝叶斯分类,所以在计算条件概率的时候使用了类似TF-IDF的思想,所以赋予权重的时候并未直接采用该方法。而是人为设定固定的权重矩阵,毕竟是某个实际垂直场景的应用,我们知道那些词汇相对重要。

2.4.建立模型

依据上面的公式,朴素贝叶斯需要知道先验概率和单个属性取值对应的条件概率,然后计算后验概率,下面是本次使用的概率计算方法。当时,这样计算的概率在文本比较稀疏的时候概率偏小,可能存在很多误差,实际展示的时候需要做归一化处理。

 1)、先验概率P(y)= 类y下单词总数/整个训练样本的单词总数
 2)、类条件概率P(xi|y)=(类y下单词xi在各个文档中出现过的次数之和+1)/(类y下单词总数+向量的维度)
 3)、P(y|xi)=P(y)*P(xi|y)/P(xi)等价于P(y)*P(xi|y)

 其中为了防止某个词语xi没有出现,导致该类的条件概率P(xi|y)为0,需要一些平滑技术,本次选择Add-one (Laplace) 平滑技术,即P(xi|y)=(类y下单词xi在各个文档中出现过的次数之和+1)/(类y下单词总数+向量的维度),保证分子不为0。关于平滑技术,也有很多地方可以考虑;当时,上面P(xi|y)的求取也借用了TF-IDF的思想。

三、代码

package com.csdn.jinxu.ChineseTextClassifier;import com.google.common.base.Splitter;
import com.google.common.collect.Maps;
import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.ToAnalysis;
import org.ansj.util.FilterModifWord;
import org.apache.commons.lang.StringUtils;import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;/*** 实现描述:ansj中文分词** @author jin.xu* @version v1.0.0* @see* @since 16-9-12 下午7:17*/
public class AnsjSpliter {/*** 分词 * @param file 文档文件或者目录* @return* @throws IOException*/public static Map<String,Integer> process(File file) throws IOException {Map<String, Integer> wordScoreMap = Maps.newHashMap();if(file.isDirectory()) {for(File tmp:file.listFiles()){Map<String,Integer> tmpWordScoreMap=process(tmp);for (Iterator iterator = tmpWordScoreMap.entrySet().iterator(); iterator.hasNext(); ) {Map.Entry entry = (Map.Entry) iterator.next();String key=(String)entry.getKey();Integer value=(Integer)entry.getValue();if (wordScoreMap.containsKey(key)) {wordScoreMap.put(key,wordScoreMap.get(key) +value);} else {wordScoreMap.put(key,value);}}}}else{BufferedReader reader = new BufferedReader(new FileReader(file));String tempString = null;while ((tempString = reader.readLine()) != null) {wordScoreMap=process(tempString,wordScoreMap);}reader.close();}return  wordScoreMap;}/*** 分词 * @param inputText 文档文本* @return* @throws IOException*/public static Map<String,Integer> process(String inputText) throws IOException {Map<String, Integer> wordScoreMap = Maps.newHashMap();process(inputText,wordScoreMap);return  wordScoreMap;}/*** 过滤停用词* @param file 停用词文件* @return* @throws IOException*/public static HashMap<String,String> filter(File file) throws IOException {BufferedReader reader = new BufferedReader(new FileReader(file));HashMap<String,String>stopWordMap= Maps.newHashMap();String tempString = null;while ((tempString = reader.readLine()) != null) {stopWordMap.put(tempString.trim() , "_stop");}reader.close();return  stopWordMap;}/*** 过滤停用词* @param inputText 停用词文本,以逗号','隔开* @return* @throws IOException*/public static HashMap<String,String> filter(String inputText) throws IOException {HashMap<String,String>stopWordMap= Maps.newHashMap();List<String> wordList= Splitter.on(',').splitToList(inputText);if(wordList.size()>0) {for (String word : wordList) {stopWordMap.put(word, "_stop");}}return  stopWordMap;}/*** 分词 * @param inputText 文档文本* @param wordScoreMap 单词-频数映射* @return* @throws IOException*/private static Map<String,Integer> process(String inputText,Map<String,Integer>wordScoreMap) throws IOException {for (Term term : FilterModifWord.modifResult(ToAnalysis.parse(inputText))) {if(StringUtils.isNotBlank(term.getName().trim())) {if (wordScoreMap.containsKey(term.getName())) {wordScoreMap.put(term.getName(), wordScoreMap.get(term.getName()) + 1);} else {wordScoreMap.put(term.getName(), 1);}}}return  wordScoreMap;}
}
package com.csdn.jinxu.ChineseTextClassifier;import java.util.Iterator;
import java.util.Map;/*** 实现描述:朴素贝叶斯分类** @author jin.xu* @version v1.0.0*          1.先验概率P(y)= 类y下单词总数/整个训练样本的单词总数*          2.类条件概率P(xi|y)=(类y下单词xi在各个文档中出现过的次数之和+1)/(类y下单词总数+向量的维度)*          3.P(y|xi)=P(y)*P(xi|y)/P(xi)等价于P(y)*P(xi|y)* @see* @since 16-9-13 下午5:44*/
public class NBClassifier {private Map<String, Double> wordWeightMap;private Map<String, Integer> yesDocMap;private Map<String, Integer> noDocMap;private double yesPrioriProb;private double noPrioriProb;private Long wordDifCount;private Long yesClassWordCount;private Long noClassWordCount;public NBClassifier(Map<String, Integer> yesDocMap, Map<String, Integer> noDocMap, Map<String, Double> wordWeightMap) {this.wordWeightMap = wordWeightMap;this.wordDifCount = (long) this.wordWeightMap.size();//?????????????????this.yesDocMap = yesDocMap;this.noDocMap = noDocMap;yesPrioriProb = 1.0 * yesDocMap.size() / (yesDocMap.size() + noDocMap.size());noPrioriProb = 1.0 * noDocMap.size() / (yesDocMap.size() + noDocMap.size());this.yesClassWordCount = getWordCount(yesDocMap);this.noClassWordCount = getWordCount(noDocMap);}/*** 增量训练** @param docMap  待加入训练集的数据* @param isbYes  对应标签*/public void train(Map<String, Integer> docMap, boolean isbYes) {if (isbYes) {this.yesDocMap = mergeDocMap(this.yesDocMap, docMap);} else {this.noDocMap = mergeDocMap(this.noDocMap, docMap);}yesPrioriProb = 1.0 * yesDocMap.size() / (yesDocMap.size() + noDocMap.size());noPrioriProb = 1.0 * noDocMap.size() / (yesDocMap.size() + noDocMap.size());this.yesClassWordCount = getWordCount(yesDocMap);this.noClassWordCount = getWordCount(noDocMap);}/*** 分类文档** @param wordFreMap  待分类文档对应的单词-频数映射* @return*/public double[] classify(Map<String, Integer> wordFreMap) {double[][] conditionalProb = new double[2][wordFreMap.size()];conditionalProb[0] = getProbMatrix(yesDocMap, yesClassWordCount, wordFreMap);conditionalProb[1] = getProbMatrix(noDocMap, noClassWordCount, wordFreMap);double[] classProb = {yesPrioriProb, noPrioriProb};for (int i = 0; i < classProb.length; ++i) {for (int j = 0; j < wordFreMap.size(); ++j) {classProb[i] *= conditionalProb[i][j];}}return classProb;}/*** 概率归一化** @param classProb  原概率列表* @return*/public double[] normalized(double[] classProb) {double[] classProbAfterNor = new double[classProb.length];double sum = 0.0;for (int i = 0; i < classProb.length; ++i) {sum += classProb[i];}for (int i = 0; i < classProb.length; ++i) {classProbAfterNor[i] = classProb[i] / sum;}return classProbAfterNor;}/*** 将文档合并到训练文档集** @param allDocMap  训练文档集* @param docMap     待增量添加文档* @return*/public Map<String, Integer> mergeDocMap(Map<String, Integer> allDocMap, Map<String, Integer> docMap) {for (Iterator iterator = docMap.entrySet().iterator(); iterator.hasNext(); ) {Map.Entry entry = (Map.Entry) iterator.next();String key = (String) entry.getKey();Integer value = (Integer) entry.getValue();if (allDocMap.containsKey(key)) {allDocMap.put(key, allDocMap.get(key) + value);} else {allDocMap.put(key, value);}}return allDocMap;}/*** 计算给定分类属性取值下每个特征属性不同取值的条件概率矩阵** @param docMap          给定分类属性取值对应的单词-频数映射* @param classWordCount 给定分类属性取值的单词总频数* @param wordFreMap      待分类文档对应的单词-频数映射* @return*/private double[] getProbMatrix(Map<String, Integer> docMap, Long classWordCount, Map<String, Integer> wordFreMap) {double[] probMatrixPerClass = new double[wordFreMap.size()];int index = 0;for (Iterator iterator = wordFreMap.entrySet().iterator(); iterator.hasNext(); ) {Map.Entry entry = (Map.Entry) iterator.next();String key = (String) entry.getKey();Long tmpCount = 0l;Double weight = 1.0;if (docMap.containsKey(key)) {tmpCount = (long) docMap.get(key);}if (this.wordWeightMap.containsKey(key)) {weight = this.wordWeightMap.get(key);}probMatrixPerClass[index++] = 1.0 * (tmpCount + 1) * weight / (classWordCount + this.wordDifCount);}return probMatrixPerClass;}/*** 计算docMap中所有单词频数和** @param docMap  单词-频数映射* @return*/private Long getWordCount(Map<String, Integer> docMap) {Long totalFrequency = 0l;for (Iterator iterator = docMap.entrySet().iterator(); iterator.hasNext(); ) {Map.Entry entry = (Map.Entry) iterator.next();totalFrequency += (Integer) entry.getValue();}return totalFrequency;}}
package com.csdn.jinxu.ChineseTextClassifier;import com.google.common.collect.Maps;
import org.ansj.util.FilterModifWord;import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;/*** 实现描述:分类入口** @author jin.xu* @version v1.0.0* @see* @since 16-9-12 下午7:22*/
public class MainApp {private static String YES_CLASS_INPUT_DIR = MainApp.class.getResource("/text/yes/").getPath();private static String NO_CLASS_INPUT_DIR = MainApp.class.getResource("/text/no/").getPath();private static String STOP_WORD_FILE = MainApp.class.getResource("/text/stop_word.txt").getPath();private static String INPUT_FILE1 = MainApp.class.getResource("/text/test.txt").getPath();public static void main(String[] args) throws IOException {HashMap<String, String> stopWordMap = AnsjSpliter.filter(new File(STOP_WORD_FILE));FilterModifWord.setUpdateDic(stopWordMap);Map<String, Integer> yesDocMap = AnsjSpliter.process(new File(YES_CLASS_INPUT_DIR));System.out.println("yesDocMap" + yesDocMap);Map<String, Integer> noDocMap = AnsjSpliter.process(new File(NO_CLASS_INPUT_DIR));System.out.println("noDocMap" + noDocMap);Map<String, Integer> testDocMap = AnsjSpliter.process(new File(INPUT_FILE1));System.out.println("testDocMap" + testDocMap);Map<String, Double> wordWeightMap = Maps.newHashMap();NBClassifier classifier = new NBClassifier(yesDocMap, noDocMap, wordWeightMap);double[] classProb = classifier.classify(testDocMap);classProb = classifier.normalized(classProb);print(classProb);classifier.train(testDocMap, false);classProb = classifier.classify(testDocMap);classProb = classifier.normalized(classProb);print(classProb);}private static void print(double[] classProb) {System.out.println("yes 概率" + classProb[0]);System.out.println("no 概率" + classProb[1]);if (classProb[0] > classProb[1]) {System.out.println("yes");} else {System.out.println("no");}}}

  源代码github地址:https://github.com/XuJin1992/ChineseTextClassifier

  路漫漫其修远兮,很多时候感觉想法比较幼稚。首先东西比较简单,其次工作也比较忙,还好周末可以抽时间处理这个。由于相关知识积累有限,欢迎大家提意见斧正,在此表示感谢!后续版本会持续更新…

中文文本分类-朴素贝叶斯相关推荐

  1. 垃圾邮件分类-朴素贝叶斯算法

    目录 一.贝叶斯公式原理 二.使用朴素贝叶斯进行文档分类 三.Python代码实现 一.贝叶斯公式原理 在基础的概率学中,经典的有求独立事件的概率以及求关联时间的概率,贝叶斯所要解决的问题就是在有条件 ...

  2. R语言垃圾邮件分类--朴素贝叶斯(机器学习)

    邮件分类练习–朴素贝叶斯 思路 数据导入 数据处理 构建训练集和测试集 词云展示 数据降维 训练模型 模型测试 提升模型 一.数据导入 文件目录为:C:\Users\kelanj\Documents\ ...

  3. Python实现文本自动分类(朴素贝叶斯方法)

    使用机器学习方法 做文档的自动分类 套路: 1.根据每个文件 生成该文件的一个特征 2.根据特征 选择 分类器 进行文本分类 3.(可选)根据 2 步结果,调整参数/特征等

  4. 基于朴素贝叶斯和LSTM的两种新闻文本分类方法

    新闻文本分类 文章目录 新闻文本分类 一.项目背景 二.数据处理与分析 三.基于机器学习的文本分类--朴素贝叶斯 1. 模型介绍 2. 代码结构 3. 结果分析 四.基于深度学习的文本分类--LSTM ...

  5. ML之NB:朴素贝叶斯Naive Bayesian算法的简介、应用、经典案例之详细攻略

    ML之NB:朴素贝叶斯Naive Bayesian算法的简介.应用.经典案例之详细攻略 目录 朴素贝叶斯Naive Bayesian算法的简介 1.朴素贝叶斯计算流程表述 2.朴素贝叶斯的优缺点 2. ...

  6. 七、朴素贝叶斯中文文本分类

    1.朴素贝叶斯中文文本分类 中文分词 停用词 朴素贝叶斯中文分类举例:新闻文档分类 朴素贝叶斯中文分类的具体过程:加载停用词.中文分词.文本向量化.模型训练和保存.模型的加载和预测. 2 中文分词 2 ...

  7. 机器学习实战(四)——基于概率论的分类方法:朴素贝叶斯

    朴素贝叶斯法 4.1 基于贝叶斯决策理论的分类方法 4.1.1 贝叶斯决策理论 4.1.2 条件概率 4.1.3 全概率公式 4.1.4 贝叶斯推断 4.1.5 朴素贝叶斯 4.2 使用朴素贝叶斯进行 ...

  8. 朴素贝叶斯实现书籍分类

    文章目录 朴素贝叶斯实现书籍分类 一.数据集 二.实现方法 二.代码 实验结果 朴素贝叶斯实现书籍分类 朴素贝叶斯是生成方法,直接找出特征输出Y和特征X的联合分布P(X,Y)P(X,Y),然后用P(Y ...

  9. 基于概率论的分类方法: 朴素贝叶斯

    朴素贝叶斯 概述 贝叶斯分类是一类分类算法的总称,这类算法均以贝叶斯定理为基础,故统称为贝叶斯分类.本章首先介绍贝叶斯分类算法的基础--贝叶斯定理.最后,我们通过实例来讨论贝叶斯分类的中最简单的一种: ...

最新文章

  1. ie下面兼容性问题的一些总结(转)
  2. python中eval与json.loads对json的处理
  3. mysql千万级大数据SQL查询优化
  4. struts的国际化
  5. 关于GeneXus封装方法Model的方法
  6. 十一届蓝桥杯国赛 美丽的2-枚举
  7. go编译库给c语言函数返回值,go语言 函数return值的几种情况
  8. 【求知探新】Unity中ShaderLab内存优化
  9. spss26没有典型相关性分析_SPSS在线_SPSSAU_SPSS典型相关分析
  10. 【snmp】测试流程
  11. 另5个你不知道的HTML5接口API
  12. Lync问题解决之前端服务器Wmf2008R2错误
  13. iText - OCR 截图识字 - 新版小幅更新
  14. Python获取当前时间
  15. Unity2D中逐帧动画的制作
  16. 两年软件开发工作总结及未来展望
  17. python导入excel加入折线图_Python之openpyxl插入折线图方法
  18. 网站收录的是域名还是服务器,网站备案的到底域名还是服务器?
  19. 网络编程、通信三要素、UDP快速入门、TCP通信、即时通信、模拟BS系统
  20. 流程引擎之Flowable简介

热门文章

  1. 只有程序员才懂的梗~
  2. 史上最口语化Arduino入门教程——1.3模拟IO口
  3. python怎么设置随机数种子_PyTorch设置随机数种子使结果可复现
  4. 哀悼!旷视首席科学家孙剑博士突然离世,终年45岁
  5. Data-URI详细介绍
  6. 源码安装zabbix5.0
  7. 自动驾驶+车联网应用落地 引领智慧出行新趋势
  8. IDEA字体大小和注释颜色修改
  9. python 1到10000的累加和_Python练习题 020:累积累加
  10. windows网络正常而虚拟机下系统ubuntu无法连接网络