Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What are the problem?

posted at

updated at

Organization

文章のジャンルを推定する方法

はじめに

この記事ではある文章からその文章が持つジャンルについて推定する方法について複数の方法を記載します.

何故必要か

自然言語処理等や自動文章生成にて様々な文章を収集して利用するケースがあるかと思います.
しかし,その文章が必ずしもジャンル分けやタグ付けされているわけではなく,あるジャンルに特化した自然言語処理や自動文章生成を行う際にはまず前処理にてジャンルを推定する必要があります.

前提条件

  • Python 3.7.9
    • FuzzyWuzzy
    • python-Levenshtein
    • mecab-python3
  • Mecab
    • mecab-ipadic-NEologd

ジャンルを推定する方法

正規表現から推定する方法

単純に正規表現等を利用し,ジャンル名がその文章に入っていれば同ジャンルと推定する方法です.

ソースコード

import re

# ジャンル名
Genre_name = 'Qiita'

# 推定したい文章
Sentence = 'Qiitaは、エンジニアに関する知識を記録・共有するためのサービスです。'

regex_sentence = '.*{}.*'.format(Genre_name)
if re.search(regex_sentence, Sentence):
    print('{} は {}に含まれています'.format(Sentence, Genre_name))

形態素解析を利用して推定する方法

ジャンル名は基本的に名詞に分類されます.それも固有名詞に分類されるケースが多いです.
そのため文章を形態素解析し,固有名詞のみを取り出しジャンル名がその中にあれば同ジャンルと推定する方法です.
今回はMecabと辞書にmecab-ipadic-NEologdを利用して行います.

ソースコード

import MeCab


def mecab_list(text):
    # /path/is/select/は辞書の位置を指定してください
    tagger = MeCab.Tagger(r'-d /path/is/select/')
    tagger.parse('')
    node = tagger.parseToNode(text)
    word_class = []
    while node:
        word = node.surface
        wclass = node.feature.split(',')
        if wclass[0] != u'BOS/EOS' and wclass[1] == '固有名詞':
            word_class.append(word)
        node = node.next
    return word_class

# ジャンル名
Genre_name = 'Qiita'

# 推定したい文章
Sentence = 'Qiitaは、エンジニアに関する知識を記録・共有するためのサービスです。'

Sentence_list = mecab_list(Sentence)

if Genre_name in Sentence_list:
    print('{} は {}に含まれています'.format(Sentence, Genre_name))

類似度検索を利用して推定する方法

レーベンシュタイン距離を利用し,その文章とジャンルの類似度を推定する方法があります.
その類似度がα以上であれば同ジャンルと推定する方法です.
今回はFuzzyWuzzyというライブラリを利用して行います.

ソースコード

from fuzzywuzzy import fuzz

# ジャンル名
Genre_name = 'Qiita'

# 推定したい文章
Sentence = 'Qiitaは、エンジニアに関する知識を記録・共有するためのサービスです。'

# 類似度の基準
Similarity_match = 90

ratio = fuzz.partial_ratio(Sentence, Genre_name)
if Similarity_match <= ratio:
    print('{} は {}に含まれています'.format(Sentence, Genre_name))

各方法の特徴

正規表現から推定する方法

比較するジャンル数が少ない場合かつジャンル名の文字数が少ない場合にはよさそうです.
しかし下記の記載にも書きますが,ジャンル推定の誤認識を招く恐れのある方法です.
またジャンル名の文字数が多い場合にはそのブランド名が短縮表現されていた際に検知することが出来ません.

形態素解析を利用して推定する方法

固有名詞を取り出すことでジャンルとしての表現かそれともそれ以外の表現かを分けることが出来るために精度が上がります.

「明治時代、学生たちの間で「アイス」と呼ばれた職業とは何?」という文章からジャンルを推定する場合,明治時代という表現がジャンル名「明治」と誤認識してしまう恐れがあります.そのため形態素解析を行うことで誤認識を減らすことが出来ます.

但し,形態素解析を行う辞書に認識率が依存する欠点もあります.そのためジャンル名が固有名詞として辞書に登録されていない場合精度が下がってしまいます.
mecab-ipadic-NEologdを利用することで緩和可能)

類似度検索を利用して推定する方法

正規表現と同じく比較するジャンルが少ない場合にはかなりよさそうです.また正規表現と違いジャンル名の文字数が多い場合にも対応できます.更に類似度の値を調整することで精度と検出率を調整することが可能です.

最後に

今回3つの方法を考えましたが,他にも様々な推定方法(Doc2Vecを利用する方法等)がありますので,
また近いうちに他の方法についても書いていきたいと思います!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
0
Help us understand the problem. What are the problem?