【问题标题】:How to extract key phrases from a given text with OpenNLP?如何使用 OpenNLP 从给定文本中提取关键短语?
【发布时间】:2015-09-09 17:33:50
【问题描述】:

我正在使用 Apache OpenNLP,我想提取给定文本的关键词。我已经在收集实体 - 但我想要关键词。

我的问题是我不能使用 TF-IDF,因为我没有模型而且我只有一个文本(不是多个文档)

这是一些代码(原型 - 不太干净)

 public List<KeywordsModel> extractKeywords(String text, NLPProvider pipeline) {

        SentenceDetectorME sentenceDetector = new SentenceDetectorME(pipeline.getSentencedetecto("en"));
        TokenizerME tokenizer = new TokenizerME(pipeline.getTokenizer("en"));
        POSTaggerME posTagger = new POSTaggerME(pipeline.getPosmodel("en"));
        ChunkerME chunker = new ChunkerME(pipeline.getChunker("en"));

        ArrayList<String> stopwords = pipeline.getStopwords("en");

        Span[] sentSpans = sentenceDetector.sentPosDetect(text);
        Map<String, Float> results = new LinkedHashMap<>();
        SortedMap<String, Float> sortedData = new TreeMap(new MapSort.FloatValueComparer(results));

        float sentenceCounter = sentSpans.length;
        float prominenceVal = 0;
        int sentences = sentSpans.length;
        for (Span sentSpan : sentSpans) {
            prominenceVal = sentenceCounter / sentences;
            sentenceCounter--;
            String sentence = sentSpan.getCoveredText(text).toString();
            int start = sentSpan.getStart();
            Span[] tokSpans = tokenizer.tokenizePos(sentence);
            String[] tokens = new String[tokSpans.length];
            for (int i = 0; i < tokens.length; i++) {
                tokens[i] = tokSpans[i].getCoveredText(sentence).toString();
            }
            String[] tags = posTagger.tag(tokens);
            Span[] chunks = chunker.chunkAsSpans(tokens, tags);
            for (Span chunk : chunks) {
                if ("NP".equals(chunk.getType())) {
                    int npstart = start + tokSpans[chunk.getStart()].getStart();
                    int npend = start + tokSpans[chunk.getEnd() - 1].getEnd();
                    String potentialKey = text.substring(npstart, npend);
                    if (!results.containsKey(potentialKey)) {
                        boolean hasStopWord = false;
                        String[] pKeys = potentialKey.split("\\s+");
                        if (pKeys.length < 3) {
                            for (String pKey : pKeys) {
                                for (String stopword : stopwords) {
                                    if (pKey.toLowerCase().matches(stopword)) {
                                        hasStopWord = true;
                                        break;
                                    }
                                }
                                if (hasStopWord == true) {
                                    break;
                                }
                            }
                        }else{
                            hasStopWord=true;
                        }
                        if (hasStopWord == false) {
                            int count = StringUtils.countMatches(text, potentialKey);
                            results.put(potentialKey, (float) (Math.log(count) / 100) + (float)(prominenceVal/5));
                        }
                    }
                }
            }
        }
        sortedData.putAll(results);
        System.out.println(sortedData);
        return null;
    }

它的基本作用是把名词归还给我,并按突出值(它在文本中的什么位置?)对它们进行排序并计数。

但老实说 - 这不太好用。

我也用lucene分析仪试了一下,结果也不是很好。

那么 - 我怎样才能实现我想做的事情?我已经知道 KEA/Maui-indexer 等(但由于 GPL,我恐怕无法使用它们:()


也很有趣?我可以使用哪些其他算法来代替 TF-IDF?

例子:

此文字:http://techcrunch.com/2015/09/04/etsys-pulling-the-plug-on-grand-st-at-the-end-of-this-month/

我认为好的输出:Etsy、Grand St.、太阳能充电器、制造商市场、技术硬件

【问题讨论】:

    标签: java lucene nlp keyword opennlp


    【解决方案1】:

    终于,我发现了一些东西:

    https://github.com/srijiths/jtopia

    它正在使用来自 opennlp/stanfordnlp 的 POS。它具有 ALS2 许可证。尚未测量精确度和召回率,但我认为它提供了很好的结果。

    这是我的代码:

     Configuration.setTaggerType("openNLP");
            Configuration.setSingleStrength(6);
            Configuration.setNoLimitStrength(5);
            // if tagger type is "openNLP" then give the openNLP POS tagger path
            //Configuration.setModelFileLocation("model/openNLP/en-pos-maxent.bin"); 
            // if tagger type is "default" then give the default POS lexicon file
            //Configuration.setModelFileLocation("model/default/english-lexicon.txt");
            // if tagger type is "stanford "
            Configuration.setModelFileLocation("Dont need that here");
            Configuration.setPipeline(pipeline);
            TermsExtractor termExtractor = new TermsExtractor();
            TermDocument topiaDoc = new TermDocument();
            topiaDoc = termExtractor.extractTerms(text);
            //logger.info("Extracted terms : " + topiaDoc.getExtractedTerms());
            Map<String, ArrayList<Integer>> finalFilteredTerms = topiaDoc.getFinalFilteredTerms();
            List<KeywordsModel> keywords = new ArrayList<>();
            for (Map.Entry<String, ArrayList<Integer>> e : finalFilteredTerms.entrySet()) {
                KeywordsModel keyword = new KeywordsModel();
                keyword.setLabel(e.getKey());
                keywords.add(keyword);
            }
    

    我稍微修改了配置文件,以便从管道实例加载 POSModel。

    【讨论】:

    • 您可以尝试评估 Precision/Recall 吗?对于处理这些现象的其他用户来说也会非常有趣:)
    • 你好 :=) 是的。我去做!可能需要一些时间,但我会回来在这里给你答案。
    • 好的 - 结果是这个库不能很好地工作,因为你不能得到分数。我最终会采用以下策略:使用 openNLP 从给定文本中提取 NP(名词短语)并将“idf”部分保存在数据库中。我正在从维基百科挖掘这些语料库。然后只需计算“tf”部分的寿命并从数据库中获取“idf”部分。我认为这应该很好用。
    猜你喜欢
    • 2019-08-16
    • 1970-01-01
    • 1970-01-01
    • 2013-11-28
    • 1970-01-01
    • 2015-03-29
    • 2020-08-16
    • 1970-01-01
    • 2022-01-09
    相关资源
    最近更新 更多