利用ANSJ进行文本关键词提取

之前已经提到过使用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.   
  7.     public Keyword(String name, int docFreq, int weight) {  
  8.         this.name = name;  
  9.         this.idf = Math.log(10000 + 10000.0 / (docFreq + 1));  
  10.         this.score = idf * weight;  
  11.         freq++;  
  12.     }  
  13.     public void updateWeight(int weight) {  
  14.         this.score += weight * idf;  
  15.         freq++;  
  16.     }  
  17.     public int compareTo(Keyword o) {  
  18.         if (this.score < o.score) {  
  19.             return 1;  
  20.         } else {  
  21.             return -1;  
  22.         }  
  23.   
  24.     }  
  25.     public boolean equals(Object obj) {  
  26.         // TODO Auto-generated method stub  
  27.         if (obj instanceof Keyword) {  
  28.             Keyword k = (Keyword) obj;  
  29.             return k.name.equals(name);  
  30.         } else {  
  31.             return false;  
  32.         }  
  33.     }  
  34.     public String toString() {  
  35.         return name;  
  36.     }  
  37.     //look here ******************************************************  
  38.     public double getScore(){  
  1.         return score;  
  2.     }  
  3.     public int getFreq() {  
  4.         return freq;  
  5.     }  
  6.   
  7. }  
除了这个之外,我们还需要原封不动地把keywordcomputer类重抄一遍,随叫这两个类息息相关呢,要么都在JAR中要么就一起跳出来。对于这个类,实在不知道计算keyword时为何要知道title的长度,作者告诉我这不是他写的也不知道缘由,我猜Github上面添加这个模块的人肯定认为出现在标题中的词需要赋予较大的权重吧,也许这个想法是对的。

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  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.   
  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.NlpAnalysis;  
  12.   
  13. public class KeyWordComputer {  
  14.     private int nKeyword = 10;  
  15.     //default constructor keyword number=10  
  16.     public KeyWordComputer() {  
  17.         nKeyword = 10;  
  18.     }  
  19.     // constructor set keyword number  
  20.     public KeyWordComputer(int nKeyword) {  
  21.         this.nKeyword = nKeyword;  
  22.   
  23.     }  
  24.     //get keywords object list  
  25.     private List<Keyword> computeArticleTfidf(String content, int titleLength) {  
  26.         Map<String, Keyword> tm = new HashMap<String, Keyword>();  
  27.         LearnTool learn = new LearnTool();  
  28.         List<Term> parse = NlpAnalysis.parse(content, learn);  
  29.         parse = NlpAnalysis.parse(content, learn);  
  30.         for (Term term : parse) {  
  31.             int weight = getWeight(term, content.length(), titleLength);  
  32.             if (weight == 0)  
  1. continue;  
  2.             Keyword keyword = tm.get(term.getName());  
  3.             if (keyword == null) {  
  4.                 keyword = new Keyword(term.getName(), term.getNatrue().allFrequency, weight);  
  5.                 tm.put(term.getName(), keyword);  
  6.             } else {  
  7.                 keyword.updateWeight(1);  
  8.             }  
  9.         }  
  10.         TreeSet<Keyword> treeSet = new TreeSet<Keyword>(tm.values());  
  11.         ArrayList<Keyword> arrayList = new ArrayList<Keyword>(treeSet);  
  12.         if (treeSet.size() < nKeyword) {  
  13.             return arrayList;  
  14.         } else {  
  15.             return arrayList.subList(0, nKeyword);  
  16.         }  
  17.     }  
  18.     //get keywords,need title and content  
  19.     public Collection<Keyword> computeArticleTfidf(String title, String content) {  
  20.         return computeArticleTfidf(title + "\t" + content, title.length());  
  21.     }  
  22.     //get keywords, just need content  
  23.     public Collection<Keyword> computeArticleTfidf(String content) {  
  24.         return computeArticleTfidf(content, 0);  
  25.     }  
  26.     //get keywords weight  
  27.     private int getWeight(Term term, int length, int titleLength) {  
  28.         if (term.getName().matches("(?s)\\d.*")) {  
  29.             return 0;  
  30.         }  
  31.         if (term.getName().trim().length() < 2) {  
  32.             return 0;  
  33.         }  
  34.         String pos = term.getNatrue().natureStr;  
  1. if (!pos.startsWith("n") || "num".equals(pos)) {  
  2.             return 0;  
  3.         }  
  4.         int weight = 0;  
  5.         if (titleLength > term.getOffe()) {  
  6.             return 20;  
  7.         }  
  8.         // position  
  9.         double position = (term.getOffe() + 0.0) / length;  
  10.         if (position < 0.05)  
  11.             return 10;  
  12.         weight += (5 - 5 * position);  
  13.         return weight;  
  14.     }  
  15. }  

3-test

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

package com.zengxiaosen;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Iterator;

/**
 * Created by zengxiaosen on 16/10/17.
 * 提取关键词语
 */
public class KeyWordtest {
    public static void main(String[] args) throws IOException{
        String filePath = "./test-utf8.TXT";
        String tt = new String();
        BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)));
        String str;
        while((str = in.readLine()) != null){
            tt += str;
        }
        test1(tt);
    }

    public static void test1(String content){
        KeyWordComputer key = new KeyWordComputer(10);
        Iterator<Keyword> it = key.computeArticleTfidf(content).iterator();
        while(it.hasNext()){
            Keyword key2 = (Keyword)it.next();
            System.out.println(key2.toString()+key2.getScore());
        }
    }
}
在测试时有一点需要注意,ANSJ目前只支持UTF-8格式的字符串,其他格式的运行时会报JAVA GC错误,作者说因为处理过程中是乱码,程序以为都是新词导致内存崩溃了,希望他在以后的版本中加以改进吧。最后给出输出结果,这里是按照权重排序的:

[plain]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  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  


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值