一、思路分析
先来分析一下思路:
本项目所用的语料库是pos.txt和neg.txt两个文件,分别代表pos(积极)和neg(消极)类别,文件中有很多条已经分好类的微博,一整行为一条。
![](https://i-blog.csdnimg.cn/blog_migrate/5eec717a0dc8b9636f7796c7466177b2.png)
1、计算tf
tf应该分类别计算。分别计算某个词在每个类别中的tf。这是什么意思呢?我们往下看。
某一个词在某种类别的tf=这类文件中这个词出现的次数/这类文件的总词数
比如:“开心”在pos类别中出现了50次,pos中一共有100个词。
“开心”在neg类别中出现了30次,neg中一共有150个词。
则“开心”在pos中的tf=50/100=1/2
“开心”在neg中的tf=30/150=1/5
2、计算idf
idf应该以总的微博条数作为计算范围(但是本项目不是这样做的,原因稍后分析)。不理解?没关系,继续往下看。
idf表示一个词语的普遍重要程度。
在语料库中,每个词的区分能力是不一样的,如果包含某一个词的微博条数越少,则说明该词具有很好的区分能力,其idf就越大。
一般来说,带有强烈感情色彩的词比中性词具有更好的区分能力,其idf一般越大。
某个词的idf=log(微博总条数/出现该词的微博条数)
比如:在pos和neg中“开心”一共出现在70条微博中,而pos和neg加起来一共有500条微博
则“开心”的idf=log(500/70)
idf的不足:有时候,若一个词在一个类别中频繁的出现,说明该词条能很好的代表这个类的特征,具有很好的区分能力。但随着它出现的次数的增多,idf会变小,idf会变小表明其区分能力弱,这与实际情况不符。
3、计算tfidf
与tf一样tfidf也是以类为单位。
某个词在某种类别中的tfidf=这个词在这个类别中的tf * 这个词的idf
比如:“开心”在pos中的tfidf=1/2 * log(50/7)
“开心”在neg中的tfidf=1/5 * log(50/7)
4、输入测试微博,进行分类
测试微博:我很开心和满足!
分词结果:“开心”、“满足”
通过语料库得出 :“开心”在pos中的tfidf=1/2 * log(50/7)
“开心”在neg中的tfidf=1/5 * log(50/7)
“满足”在pos中的tfidf=0.6
满足”在neg中的tfidf=0.5
这句话的得分等于每个词的tfidf之和。在哪个类别中得分更高,这句话就被分为哪一类。
所以这句话的pos得分:P=1/2 * log(50/7)+ 0.6
neg得分:N=1/5 * log(50/7)+ 0.5
因为P>N,所以这句话被归为pos类。
二、算法的程序实现
我们再来看一下如何写程序:
分类中的几个步骤
1 对我们的语料库(训练文本)进行分词
2 对分词之后的文本进行TF-IDF的计算(TF-IDF介绍可以参考这边文章http://blog.csdn.net/yqlakers/article/details/70888897)
3 利用计算好的TF-IDF进行分类
分词器:
- <span style="font-family:'KaiTi_GB2312';">package tfidf;
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.FileReader;
- import java.io.IOException;
- import org.apache.lucene.analysis.TokenStream;
- import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
- import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
- import org.apache.lucene.analysis.util.CharArraySet;
- import org.apache.lucene.util.Version;
- public class MMAnalyzer {
- public MMAnalyzer() {
- // TODO Auto-generated constructor stub
- }
- public String segment(String splitText, String str) throws IOException{
- BufferedReader reader = new BufferedReader(new FileReader(new File("F:/Porject/Hadoop project/TDIDF/TFIDF/TFIDF/stop_words.txt")));
- String line = reader.readLine();
- String wordString = "";
- while(line!=null){
- //System.out.println(line);
- wordString = wordString + " " + line;
- line = reader.readLine();
- }
- String[] self_stop_words = wordString.split(" ");
- //String[] self_stop_words = { "我","你","他","它","她","的", "了", "呢", ",", "0", ":", ",", "是", "流","!"};
- CharArraySet cas = new CharArraySet(Version.LUCENE_46, 0, true);
- for (int i = 0; i < self_stop_words.length; i++) {
- cas.add(self_stop_words[i]);
- }
- @SuppressWarnings("resource")
- SmartChineseAnalyzer sca = new SmartChineseAnalyzer(Version.LUCENE_46, cas);
- //分词器做好处理之后得到的一个流,这个流中存储了分词的各种信息.可以通过TokenStream有效的获取到分词单元
- TokenStream ts = sca.tokenStream("field", splitText);
- // 语汇单元对应的文本
- //CharTermAttribute ch = ts.addAttribute(CharTermAttribute.class);
- //Resets this stream to the beginning.
- ts.reset();
- // 递归处理所有语汇单元
- //Consumers (i.e., IndexWriter) use this method to advance the stream to the next token.
- String words = "";
- while (ts.incrementToken()) {
- String word = ts.getAttribute(CharTermAttribute.class).toString();
- System.out.println(word);
- words = words + word + ' ';
- //System.out.println(ch.toString());
- }
- ts.end();
- ts.close();
- return words;
- }
- }</span>
这里的分词采用的是SmartChineseAnalyzer分词器,加上自己去网上找了点stopwords的素材,通过这样的方式对微博文本进行分词