入力テキストからキーワードを抽出するためのJavaライブラリ [closed] 質問する

入力テキストからキーワードを抽出するためのJavaライブラリ [closed] 質問する

テキストブロックからキーワードを抽出する Java ライブラリを探しています。

プロセスは次のようになります。

ストップワードのクリーニング -> ステミング -> 英語の言語学統計情報に基づいたキーワードの検索 - つまり、単語が英語よりもテキスト内で多く出現する確率が高い場合は、それがキーワード候補となります。

このタスクを実行するライブラリはありますか?

ベストアンサー1

ここで考えられる解決策はApache ルシーン最後のバージョンは使用しませんでしたが、3.6.2 1つ、これが私が最もよく知っているものだからです。 のほかに/lucene-core-x.x.x.jar、ダウンロードしたアーカイブから をプロジェクトに追加することも忘れないでください/contrib/analyzers/common/lucene-analyzers-x.x.x.jar。これには言語固有のアナライザー (特にあなたの場合は英語のアナライザー) が含まれています。

これはのみ入力テキストの単語の頻度をそれぞれの語幹に基づいて調べます。これらの頻度を英語の統計と比較するのは後で行います(この答えちなみに役に立つかもしれません。


データモデル

1 つの語幹に 1 つのキーワード。異なる単語が同じ語幹を持つ場合があるため、termsセットになります。キーワードの頻度は、新しい用語が見つかるたびに増加します (すでに見つかっている場合でも、セットによって重複が自動的に削除されます)。

public class Keyword implements Comparable<Keyword> {

  private final String stem;
  private final Set<String> terms = new HashSet<String>();
  private int frequency = 0;

  public Keyword(String stem) {
    this.stem = stem;
  }

  public void add(String term) {
    terms.add(term);
    frequency++;
  }

  @Override
  public int compareTo(Keyword o) {
    // descending order
    return Integer.valueOf(o.frequency).compareTo(frequency);
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    } else if (!(obj instanceof Keyword)) {
      return false;
    } else {
      return stem.equals(((Keyword) obj).stem);
    }
  }

  @Override
  public int hashCode() {
    return Arrays.hashCode(new Object[] { stem });
  }

  public String getStem() {
    return stem;
  }

  public Set<String> getTerms() {
    return terms;
  }

  public int getFrequency() {
    return frequency;
  }

}

ユーティリティ

単語の語幹を抽出するには:

public static String stem(String term) throws IOException {

  TokenStream tokenStream = null;
  try {

    // tokenize
    tokenStream = new ClassicTokenizer(Version.LUCENE_36, new StringReader(term));
    // stem
    tokenStream = new PorterStemFilter(tokenStream);

    // add each token in a set, so that duplicates are removed
    Set<String> stems = new HashSet<String>();
    CharTermAttribute token = tokenStream.getAttribute(CharTermAttribute.class);
    tokenStream.reset();
    while (tokenStream.incrementToken()) {
      stems.add(token.toString());
    }

    // if no stem or 2+ stems have been found, return null
    if (stems.size() != 1) {
      return null;
    }
    String stem = stems.iterator().next();
    // if the stem has non-alphanumerical chars, return null
    if (!stem.matches("[a-zA-Z0-9-]+")) {
      return null;
    }

    return stem;

  } finally {
    if (tokenStream != null) {
      tokenStream.close();
    }
  }

}

コレクションを検索するには(潜在的なキーワードのリストで使用されます):

public static <T> T find(Collection<T> collection, T example) {
  for (T element : collection) {
    if (element.equals(example)) {
      return element;
    }
  }
  collection.add(example);
  return example;
}

主な入力方法は次のとおりです。

public static List<Keyword> guessFromString(String input) throws IOException {

  TokenStream tokenStream = null;
  try {

    // hack to keep dashed words (e.g. "non-specific" rather than "non" and "specific")
    input = input.replaceAll("-+", "-0");
    // replace any punctuation char but apostrophes and dashes by a space
    input = input.replaceAll("[\\p{Punct}&&[^'-]]+", " ");
    // replace most common english contractions
    input = input.replaceAll("(?:'(?:[tdsm]|[vr]e|ll))+\\b", "");

    // tokenize input
    tokenStream = new ClassicTokenizer(Version.LUCENE_36, new StringReader(input));
    // to lowercase
    tokenStream = new LowerCaseFilter(Version.LUCENE_36, tokenStream);
    // remove dots from acronyms (and "'s" but already done manually above)
    tokenStream = new ClassicFilter(tokenStream);
    // convert any char to ASCII
    tokenStream = new ASCIIFoldingFilter(tokenStream);
    // remove english stop words
    tokenStream = new StopFilter(Version.LUCENE_36, tokenStream, EnglishAnalyzer.getDefaultStopSet());

    List<Keyword> keywords = new LinkedList<Keyword>();
    CharTermAttribute token = tokenStream.getAttribute(CharTermAttribute.class);
    tokenStream.reset();
    while (tokenStream.incrementToken()) {
      String term = token.toString();
      // stem each term
      String stem = stem(term);
      if (stem != null) {
        // create the keyword or get the existing one if any
        Keyword keyword = find(keywords, new Keyword(stem.replaceAll("-0", "-")));
        // add its corresponding initial token
        keyword.add(term.replaceAll("-0", "-"));
      }
    }

    // reverse sort by frequency
    Collections.sort(keywords);

    return keywords;

  } finally {
    if (tokenStream != null) {
      tokenStream.close();
    }
  }

}

このguessFromString方法を使用するとJava Wikipedia記事紹介部分見つかった最も頻繁なキーワード(語幹)の最初の 10 個は次のとおりです。

java         x12    [java]
compil       x5     [compiled, compiler, compilers]
sun          x5     [sun]
develop      x4     [developed, developers]
languag      x3     [languages, language]
implement    x3     [implementation, implementations]
applic       x3     [application, applications]
run          x3     [run]
origin       x3     [originally, original]
gnu          x3     [gnu]

出力リストを反復処理して、どれがオリジナルの単語各語幹について、termsセットを取得します ([...]上記の例では括弧内に表示されています)。


次は何ですか

比較する語幹頻度 / 頻度合計英語の統計の比率と、それを管理できた場合は私に知らせてください。私も非常に興味があります:)

おすすめ記事