テキストデータ抽出テクニック

テキストパターン解析によるアスペクトベース感情の効率的な抽出方法

Tags: Python, NLP, SpaCy, 情報抽出, 感情分析, テキスト分析, 依存構造解析

はじめに

顧客レビュー、アンケート回答、SNSでの意見など、テキストデータには製品やサービスに対するユーザーの多様な評価が含まれています。これらの評価を分析する際、単にポジティブかネガティブかを判定するだけでは不十分な場合があります。例えば、「このノートPCのキーボードは打ちやすいが、バッテリー持ちは悪い」というレビューでは、キーボードはポジティブ、バッテリーはネガティブと、異なる対象(アスペクト)に対して異なる感情が述べられています。

このような場合、特定の「アスペクト」(製品の機能、サービスの側面など)がどのような感情と共に語られているかを詳細に把握する「アスペクトベース感情分析(Aspect-Based Sentiment Analysis: ABSA)」が有効です。ABSAは、テキスト中からアスペクトを特定し、さらにそのアスペクトに対する感情(ポジティブ、ネガティブ、ニュートラルなど)を抽出するタスクです。

ABSAを実現するためのアプローチはいくつかありますが、本記事では特に、テキストの構造(単語間の関係性)に着目した「テキストパターン解析」による情報抽出手法に焦点を当てます。Pythonと自然言語処理ライブラリを活用し、具体的なコード例を通して、この手法の実装方法と実務への応用について解説します。

アスペクトベース感情分析におけるパターン解析の基本

アスペクトベース感情分析において、テキストパターン解析が果たす役割は主に以下の2点です。

  1. アスペクトの特定: テキスト中で、評価の対象となっている名詞や名詞句(例:「カメラ」「バッテリー持ち」「サポート」)を特定します。
  2. 感情語の特定とアスペクトへの紐付け: 特定されたアスペクトに対して、どのような感情を表す形容詞や動詞(例:「素晴らしい」「ひどい」「速い」「遅い」)が結びついているかを特定し、その関係性を捉えます。

多くの場合、アスペクトとそれに係る感情語は、文中で比較的近くに位置したり、特定の文法的な関係性を持ったりします。例えば、「[アスペクト] は [感情語] です」や、「[感情語] [アスペクト]」といったパターンがよく見られます。これらのパターンを捉えるために、単語の品詞情報や、単語間の依存関係(係り受け構造)が非常に有効です。

依存関係解析とは、文中の単語が文法的にどのように修飾し合ったり、支配し合ったりしているかを解析する技術です。これにより、「バッテリー持ち」という名詞が「悪い」という形容詞の主語となっている、あるいは「悪い」という形容詞が「バッテリー持ち」という名詞を修飾している、といった関係性を構造的に把握できます。

SpaCyを用いた依存関係解析とパターン抽出

Pythonの主要なNLPライブラリであるSpaCyは、高速かつ高精度な依存関係解析機能を提供しており、アスペクトベース感情分析におけるパターン解析に適しています。

SpaCyを使って依存関係を解析する基本的な流れは以下の通りです。

  1. 日本語モデルをロードする。
  2. 対象となるテキストをSpaCyで処理し、Docオブジェクトを生成する。
  3. Docオブジェクト内の各トークン(単語)の情報を参照する(テキスト、品詞、依存関係ラベル、係り元/係り先など)。

具体的なコードを見てみましょう。

import spacy

# 日本語モデルをロード
# モデルをダウンロードしていない場合は、事前にターミナル等で
# python -m spacy download ja_core_news_sm
# を実行してください。
try:
    nlp = spacy.load("ja_core_news_sm")
except OSError:
    print("日本語モデル 'ja_core_news_sm' が見つかりません。ダウンロードしてください。")
    print("python -m spacy download ja_core_news_sm")
    exit()

text = "このスマホのカメラは素晴らしいが、バッテリー持ちはひどいです。"

# SpaCyでテキストを処理
doc = nlp(text)

# 各トークンの情報を表示
print("text\tpos\tdep\thead.text")
print("-" * 30)
for token in doc:
    # token.text: 単語テキスト
    # token.pos_: 品詞 (Universal POS)
    # token.dep_: 依存関係ラベル
    # token.head.text: 係り先の単語テキスト
    print(f"{token.text}\t{token.pos_}\t{token.dep_}\t{token.head.text}")

実行結果(依存関係ラベルや係り先はモデルバージョンによって異なる場合がありますが、構造は概ね同様です):

text    pos dep head.text
------------------------------
この  DET det スマホ
スマホ NOUN    nsubj   素晴らしい
の   ADP case    スマホ
カメラ NOUN    nsubj   素晴らしい
は   ADP case    カメラ
素晴らしい   ADJ ROOT    素晴らしい
が   CCONJ   cc  素晴らしい
、   PUNCT   punct   が
バッテリー   NOUN    compound    持ち
持ち  NOUN    nsubj   ひどい
は   ADP case    持ち
ひどい ADJ conj    素晴らしい
です  AUX aux ひどい
。   PUNCT   punct   です

この結果から、「カメラ」と「素晴らしい」がどちらも「素晴らしい」に係っていること、「バッテリー持ち」と「ひどい」が「ひどい」に係っていることが分かります。より詳細な依存関係を追うことで、アスペクト(名詞)とそれに修飾される感情語(形容詞など)のペアを抽出できます。

アスペクトと感情語のペア抽出ロジック

アスペクトと感情語のペアを抽出するための基本的なロジックは、依存関係グラフ上でアスペクト候補(名詞など)と感情語候補(形容詞など)の関係性を探索することです。

よくあるパターンとして、以下が考えられます。

今回は、シンプルに「名詞が、それに係っている形容詞や形容動詞の主語となっているパターン」、または「名詞が、それに係っている形容詞や形容動詞によって修飾されているパターン」を抽出してみましょう。

まず、アスペクト候補として名詞、感情語候補として形容詞や形容動詞を特定します。そして、それぞれの候補間で依存関係を調べます。

def extract_aspect_sentiment_pairs(doc):
    """
    SpaCy Docオブジェクトからアスペクトと感情語のペアを抽出する
    簡単なパターンマッチングによる
    """
    pairs = []
    aspect_candidates = [token for token in doc if token.pos_ in ["NOUN", "PROPN"]] # 名詞、固有名詞をアスペクト候補に
    sentiment_candidates = [token for token in doc if token.pos_ in ["ADJ", "ADV", "VERB", "AUX"]] # 形容詞、副詞、動詞、助動詞を感情語候補に (広めに取る)

    for aspect in aspect_candidates:
        # アスペクトに直接係っている単語を調べる
        for child in aspect.children:
            # 子要素が感情語候補かつ、アスペクトがその感情語のnsubjになっている場合
            if child in sentiment_candidates and aspect.dep_ in ["nsubj", "obl", "obj", "iobj"] and child.head == aspect:
                 # このパターンは逆に、形容詞が名詞を修飾している場合が多い
                 # ここではシンプルに「アスペクトに直接係っている感情語候補」をペアとする
                 # 依存関係の種類によってはより複雑な判定が必要
                 pairs.append((aspect.text, child.text, child.dep_)) # (アスペクト, 感情語, 依存関係ラベル)

        # アスペクトの係り先(head)の単語を調べる
        head = aspect.head
        # 係り先が感情語候補の場合
        if head in sentiment_candidates:
             # アスペクトがその感情語の主語になっている場合など
             if aspect.dep_ in ["nsubj", "obl", "obj", "iobj"] and head.dep_ == "ROOT" or head.dep_ == "conj": # 主語や目的語などとして係っていて、係り先が文の根や並列関係の場合
                 pairs.append((aspect.text, head.text, aspect.dep_)) # (アスペクト, 感情語, 依存関係ラベル)
             # 感情語がアスペクトを修飾している場合 (例: 「良い カメラ」)
             elif head.dep_ == "amod" and head in sentiment_candidates: # 形容詞などによる名詞修飾
                  pairs.append((aspect.text, head.text, head.dep_))

    # シンプルな辞書による感情極性判定(ここでは例として簡単な辞書を使用)
    # 実際にはより網羅的で洗練された感情辞書や機械学習モデルが必要です
    sentiment_dict = {
        "素晴らしい": "Positive", "ひどい": "Negative", "良い": "Positive", "悪い": "Negative",
        "速い": "Positive", "遅い": "Negative", "高い": "Negative", "安い": "Positive",
        "使いやすい": "Positive", "使いにくい": "Negative"
    }

    result = []
    for aspect, sentiment_word, dep in pairs:
        polarity = sentiment_dict.get(sentiment_word, "Neutral")
        result.append({
            "aspect": aspect,
            "sentiment_word": sentiment_word,
            "dependency_label": dep,
            "polarity": polarity
        })

    return result

# テキストを処理してペアを抽出
doc = nlp(text)
extracted_info = extract_aspect_sentiment_pairs(doc)

print("\nExtracted Aspect-Sentiment Pairs:")
for item in extracted_info:
    print(item)

上記のコードは簡略化されたパターンマッチングですが、「カメラ」と「素晴らしい」、「バッテリー持ち」と「ひどい」といったペアを抽出できる可能性があります。抽出されたペアに対して、別途用意した感情辞書や機械学習モデルを用いて感情極性を判定することで、アスペクトごとの感情を特定します。

例として、上記コードを実行すると(モデルの特性により変動し得ますが)、「カメラ」が「素晴らしい」に係り、その関係性が抽出され、感情極性が「Positive」と判定される可能性があります。「バッテリー持ち」についても同様です。

実務への応用

このパターン解析に基づくアスペクトベース感情抽出手法は、以下のような実務課題に応用できます。

考慮事項と限界

テキストパターン解析によるアスペクトベース感情抽出はシンプルで直感的ですが、いくつかの考慮事項と限界があります。

より高度なアスペクトベース感情分析を実現するためには、本手法をベースとしつつ、機械学習モデル(例:Transformerベースのモデルを使った分類や系列ラベリング)や、より洗練されたルールベースのアプローチ(構文解析ツリーのトラバーサル、より複雑なパターンの定義)を組み合わせることも検討すべきです。

まとめ

本記事では、テキストパターン、特に単語間の依存関係を利用したアスペクトベース感情の抽出手法について解説しました。PythonとSpaCyを用いることで、テキストから評価対象(アスペクト)とそれに対する感情語を特定し、アスペクトごとの感情を分析するための基礎を築くことができます。

この手法は、比較的少ない教師データでも実装可能であり、特定の明確な表現パターンが多いドメインにおいては強力なツールとなります。一方で、言語の多様性に対応するためには、パターンの拡張や他の手法との組み合わせが重要です。

実務でテキストデータからより詳細な情報を引き出したいとお考えのエンジニアの皆様にとって、本記事がアスペクトベース感情分析への第一歩となる知識や実装のヒントとなれば幸いです。