1.5 tf-idf权重计算

tf-idf中文称为词频-逆文档频率,用以计算词项对于一个文档集或一个语料库中的一份文件的重要程度。词项的重要性随着它在文档中出现的次数成正比增加,但同时会随着它在文档集中出现的频率成反比下降。换句话说,如果一个词项在一篇文档中出现的频率非常高,说明其重要性比较高,但是如果这个词项在文档集中的其他的文档中出现的频率也很高,那么说明这个词语有可能是比较通用比较常见的。

tf(term frequency)代表词项频率,要想计算一份文档中某个词的词频,统计该词在整篇文档中出现的次数即可。文档有长短之分,举个例子,一篇3000字的文章中词语“足球”出现了3次,我们很难断定这篇文章就是和足球相关的,但是一篇140字的微博中同样出现三次“足球”,基本可以断定微博内容和足球有关。为了削弱文档长度的影响,需要将词频标准化,计算方法如下:

另外,词频标准化的方法不止一种,Lucene中采用了另外一种词频标准化方法:

文档频率用df(document frequency)表示,代表文档集中包含某个词的所有文档数目。df通常比较大,把它映射到一个较小的取值范围,用逆文档频率(inverse document frequency,缩写为idf)来表示:

上式中分母越大,说明该词越常见,逆文档频率越小。分母中文档数加1是进行平滑处理,防止所有文档都不包含某个词时分母为0的情况发生。词项的权重用TF-IDF来表示,计算公式如下:

通过tf-idf可以把文档表示成n维的词项权重向量:

计算词项的tf-idf的Java代码如代码清单1-1所示。在TfIdfCal类中依次定义了计算词项频率tf、文档频率df、逆文档频率idf、tf-idf的方法,在main方法中以表1-4中的文档作为测试的文档集合,最后依次输出“谷歌”的词项频率、文档频率和tf-idf值。

代码清单1-1

        import java.util.Arrays;
        import java.util.List;
        public class TfIdfCal {
            public double tf(List<String> doc, String term){
              double termFrequency = 0;
              for(String str : doc){
                  if(str.equalsIgnoreCase(term)){
                      termFrequency++;
                  }
              }
              return termFrequency / doc.size();
            }
            public int df(List<List<String>> docs, String term){
              int n = 0;
              if(term ! = null && term ! = ""){
                  for(List<String> doc : docs){
                      for(String word : doc){
                          if(term.equalsIgnoreCase(word)){
                            n++;
                            break;
                          }
                      }
                  }
              } else {
                  System.out.println("term不能为null或者空串");
              }
              return n;
            }
            public double idf(List<List<String>> docs, String term){
                return  Math.log(docs.size()/(double)df(docs, term)+1);
            }
            public double tfIdf(List<String> doc, List<List<String>>
                docs, String term){
                return tf(doc, term)* idf(docs, term);
            }
            public static void main(String[] args){
              List<String> doc1 = Arrays.asList("人工", "智能", "成为",
                                  "互联网", "大会", "焦点");
              List<String> doc2 = Arrays.asList("谷歌", "推出", "开源",
                                  "人工", "智能", "系统", "工具");
              List<String> doc3 = Arrays.asList("互联网", "的", "未来",
                                  "在", "人工", "智能");
              List<String> doc4 = Arrays.asList("谷歌", "开源", "机器",
                                  "学习", "工具");
              List<List<String>> documents = Arrays.asList(doc1, doc2,
                                  doc3, doc4);
              TfIdfCal calculator = new TfIdfCal();
              System.out.println(calculator.tf(doc2, "谷歌"));
              System.out.println(calculator.df(documents, "谷歌"));
              double tfidf = calculator.tfIdf(doc2, documents, "谷歌");
              System.out.println("TF-IDF(谷歌)= " + tfidf);
            }
        }