Tag Archives: Anjs

[repost ]利用Anjs进行新闻关键词提取

original:http://blog.csdn.net/zhaoxinfan/article/details/10403917

之前已经提到过使用FudanNLP进行新闻关键词提取,无奈组长不满意于是换成了ictclas,在我的ubuntu13.04上面ictclas跑得很好,可惜到别人的机器上就报错,没办法,只好再一次换工具,经过晓阳童鞋推荐,这次换成了ANSJ,据说这个工具就是早先ictclas的JAVA版本。

这个工具的Github地址是这里:https://github.com/ansjsun/ansj_seg 需要看源码的自己前往。下面说说如何使用这个工具提取关键词。

1-下载JAR包

显然下载JAR包是最省事的方法,当然你也可以把Github上面的工程加进来,无奈JAR包找了好久未找到,最后只好向作者索取,目前已经上传到CSDN了,欢迎下载:http://download.csdn.net/detail/jj12345jj198999/6020541

2-自定义keyword类

虽然ANSJ中已经实现了关键词提取,不过输出时并没有给出每一个关键词的权重,于是只好手动修改keyword类,好在Github上面的源码中已经定义了权重成员,我们只需要增加一个Get函数即可。

 

  1. public class Keyword implements Comparable<Keyword> {
  2.     private String name;
  3.     private double score;
  4.     private double idf;
  5.     private int freq;
  6.     public Keyword(String name, int docFreq, int weight) {
  7.         this.name = name;
  8.         this.idf = Math.log(10000 + 10000.0 / (docFreq + 1));
  9.         this.score = idf * weight;
  10.         freq++;
  11.     }
  12.     public void updateWeight(int weight) {
  13.         this.score += weight * idf;
  14.         freq++;
  15.     }
  16.     public int compareTo(Keyword o) {
  17.         if (this.score < o.score) {
  18.             return 1;
  19.         } else {
  20.             return -1;
  21.         }
  22.     }
  23.     public boolean equals(Object obj) {
  24.         // TODO Auto-generated method stub
  25.         if (obj instanceof Keyword) {
  26.             Keyword k = (Keyword) obj;
  27.             return k.name.equals(name);
  28.         } else {
  29.             return false;
  30.         }
  31.     }
  32.     public String toString() {
  33.         return name;
  34.     }
  35.     //look here ******************************************************
  36.     public double getScore(){
  37.         return score;
  38.     }
  39.     public int getFreq() {
  40.         return freq;
  41.     }
  42. }

除了这个之外,我们还需要原封不动地把keywordcomputer类重抄一遍,随叫这两个类息息相关呢,要么都在JAR中要么就一起跳出来。对于这个类,实在不知道计算keyword时为何要知道title的长度,作者告诉我这不是他写的也不知道缘由,我猜Github上面添加这个模块的人肯定认为出现在标题中的词需要赋予较大的权重吧,也许这个想法是对的。

 

 

  1. import java.util.ArrayList;
  2. import java.util.Collection;
  3. import java.util.HashMap;
  4. import java.util.List;
  5. import java.util.Map;
  6. import java.util.TreeSet;
  7. import org.ansj.app.newWord.LearnTool;
  8. import org.ansj.domain.Term;
  9. import org.ansj.recognition.NatureRecognition;
  10. import org.ansj.splitWord.analysis.NlpAnalysis;
  11. public class KeyWordComputer {
  12.     private int nKeyword = 10;
  13.     //default constructor keyword number=10
  14.     public KeyWordComputer() {
  15.         nKeyword = 10;
  16.     }
  17.     // constructor set keyword number
  18.     public KeyWordComputer(int nKeyword) {
  19.         this.nKeyword = nKeyword;
  20.     }
  21.     //get keywords object list
  22.     private List<Keyword> computeArticleTfidf(String content, int titleLength) {
  23.         Map<String, Keyword> tm = new HashMap<String, Keyword>();
  24.         LearnTool learn = new LearnTool();
  25.         List<Term> parse = NlpAnalysis.parse(content, learn);
  26.         parse = NlpAnalysis.parse(content, learn);
  27.         for (Term term : parse) {
  28.             int weight = getWeight(term, content.length(), titleLength);
  29.             if (weight == 0)
  30.                 continue;
  31.             Keyword keyword = tm.get(term.getName());
  32.             if (keyword == null) {
  33.                 keyword = new Keyword(term.getName(), term.getNatrue().allFrequency, weight);
  34.                 tm.put(term.getName(), keyword);
  35.             } else {
  36.                 keyword.updateWeight(1);
  37.             }
  38.         }
  39.         TreeSet<Keyword> treeSet = new TreeSet<Keyword>(tm.values());
  40.         ArrayList<Keyword> arrayList = new ArrayList<Keyword>(treeSet);
  41.         if (treeSet.size() < nKeyword) {
  42.             return arrayList;
  43.         } else {
  44.             return arrayList.subList(0, nKeyword);
  45.         }
  46.     }
  47.     //get keywords,need title and content
  48.     public Collection<Keyword> computeArticleTfidf(String title, String content) {
  49.         return computeArticleTfidf(title + “\t” + content, title.length());
  50.     }
  51.     //get keywords, just need content
  52.     public Collection<Keyword> computeArticleTfidf(String content) {
  53.         return computeArticleTfidf(content, 0);
  54.     }
  55.     //get keywords weight
  56.     private int getWeight(Term term, int length, int titleLength) {
  57.         if (term.getName().matches(“(?s)\\d.*”)) {
  58.             return 0;
  59.         }
  60.         if (term.getName().trim().length() < 2) {
  61.             return 0;
  62.         }
  63.         String pos = term.getNatrue().natureStr;
  64.         if (!pos.startsWith(“n”) || “num”.equals(pos)) {
  65.             return 0;
  66.         }
  67.         int weight = 0;
  68.         if (titleLength > term.getOffe()) {
  69.             return 20;
  70.         }
  71.         // position
  72.         double position = (term.getOffe() + 0.0) / length;
  73.         if (position < 0.05)
  74.             return 10;
  75.         weight += (5 – 5 * position);
  76.         return weight;
  77.     }
  78. }

 

3-test

最后就是写一个类测试,import一堆东西

 

  1. import java.util.List;
  2. import java.io.BufferedReader;
  3. import java.io.FileInputStream;
  4. import java.io.IOException;
  5. import java.io.InputStreamReader;
  6. import java.io.StringReader;
  7. import java.util.Iterator;
  8. import org.ansj.app.newWord.LearnTool;
  9. import org.ansj.domain.Term;
  10. import org.ansj.recognition.NatureRecognition;
  11. import org.ansj.splitWord.Analysis;
  12. import org.ansj.splitWord.analysis.NlpAnalysis;
  13. import org.ansj.splitWord.analysis.ToAnalysis;
  14. import org.ansj.util.*;
  15. import org.ansj.recognition.*;
  16. public class test {
  17.     public static void main(String[] args) throws IOException {
  18.         String filePath = “./test-utf8.TXT”;
  19.         String tt=new String();
  20.         BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), “UTF8”));
  21.         String str;
  22.         while ((str = in.readLine()) != null) {
  23.             tt+=str;
  24.         }
  25.        test1(tt);
  26.        System.out.println(“*************************”);
  27.        filePath = “./test1.txt”;
  28.        BufferedReader in2 = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), “UTF8”));
  29.        String str2;
  30.        String tt2=new String();
  31.        while ((str2 = in2.readLine()) != null) {
  32.             tt2+=str2;
  33.        }
  34.        test1(tt2);
  35.     }
  36.     public static void test1(String content){
  37.         KeyWordComputer key=new KeyWordComputer(10);
  38.         Iterator it = key.computeArticleTfidf(content).iterator() ;
  39.         while(it.hasNext()) {
  40.             Keyword key2=(Keyword)it.next();
  41.             System.out.println(key2.toString()+key2.getScore());
  42.         }
  43.     }
  44. }

在测试时有一点需要注意,ANSJ目前只支持UTF-8格式的字符串,其他格式的运行时会报JAVA GC错误,作者说因为处理过程中是乱码,程序以为都是新词导致内存崩溃了,希望他在以后的版本中加以改进吧。最后给出输出结果,这里是按照权重排序的:

 

 

  1. init ambiguity  waring :library/ambiguity.dic because : not find that file or can not to read !
  2. init core library ok use time :3983
  3. init ngram ok use time :2023
  4. 屌丝528.8693014046396
  5. 李毅202.62858475668492
  6. 网络174.9965471938941
  7. 球迷110.52413506982782
  8. 群体110.52413506982782
  9. 人人110.52413506982782
  10. 名号101.31379048067551
  11. 高富帅92.10390216212956
  12. 满屏92.10390216212954
  13. 网友92.1034458915232
  14. *************************
  15. 社会主义1446.0241004969153
  16. 社会1326.289620837935
  17. 中国1096.0347881537828
  18. 人民1049.9792831633652
  19. 文化874.9827359694709
  20. 经济874.9827359694709
  21. 特色847.3517022020139
  22. 制度801.2999792562523
  23. 体系746.0379117213383
  24. 国家598.6723982949011