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

PythonとNLPによる業務テキストからの要望・提案抽出テクニック

Tags: Python, 自然言語処理, 情報抽出, SpaCy, テキスト分析

はじめに:業務テキストに埋もれた要望・提案を見つけ出す重要性

日々の業務で扱うテキストデータの中には、製品やサービスへの要望、改善提案、あるいは問題提起など、ビジネスの成長に繋がる重要な情報が数多く含まれています。顧客からのフィードバック、社内アンケートの自由記述、会議の議事録、サポート問い合わせ内容など、その発生源は多岐にわたります。

これらの非構造化テキストから、手作業で一つ一つ重要な情報をピックアップするのは非常に手間がかかり、網羅性にも限界があります。特にテキスト量が膨大になるにつれて、この課題は深刻化します。

本記事では、Pythonと自然言語処理(NLP)の技術を活用し、業務テキストから要望や提案といった特定の意図や内容を含む箇所を効率的に抽出するための実践的なテクニックをご紹介します。正規表現、キーワード辞書、そして軽量なNLPライブラリを組み合わせることで、経験が少ない方でも取り組みやすいアプローチを中心に解説いたします。

要望・提案抽出の基本的なアプローチ

要望や提案を含むテキストには、特徴的な表現や構造が現れることが少なくありません。例えば、「〜してほしい」「〜べきだ」「改善してはどうだろうか」「〜を希望します」「〜が良い」といった特定のフレーズや、それに類する表現が含まれることが多いです。

これらの特徴を手がかりに情報抽出を行うアプローチとして、主に以下のものが考えられます。

  1. キーワード・フレーズマッチング: 特定の単語やフレーズ(例:「改善」「要望」「希望」「〜ほしい」)に合致するかどうかを単純に判定する。
  2. パターンマッチング(正規表現): 特定の単語だけでなく、その周辺の表現も含めた柔軟なパターン(例:「〜を改善してほしい」「[何か] + [改善する] + [要望する] 系の動詞」)を正規表現で定義してマッチングする。
  3. 辞書ベース: 要望や提案と関連性の高い単語や語彙(例:「機能追加」「使いやすさ」「パフォーマンス」「改善」「提案する」「修正」)の辞書を作成し、テキスト中にこれらの語彙が特定の組み合わせで出現するかどうかを確認する。
  4. NLPによる構造分析: 品詞、依存関係、固有表現などのNLP解析結果を利用し、文の構造から要望や提案のパターンを捉える。例えば、「(ユーザー)は(システム/機能)の(属性)を(望む/改善する)という意図を持つ」といった構造を抽出する。

これらのアプローチは単独で使用することも可能ですが、組み合わせて利用することで、より高い精度と網羅性を実現できる場合が多くあります。本記事では、これらのアプローチをPythonを使ってどのように実現するかを解説します。

Pythonによる実装例

ここでは、Pythonの標準ライブラリであるre(正規表現)と、比較的軽量で依存解析まで可能なspaCyライブラリを用いた実装例をご紹介します。SpaCyの基本的な使い方については、他の記事や公式ドキュメントを参照してください。インストールはpip install spacyで行い、モデルはpython -m spacy download ja_core_news_sm(日本語の場合)などでダウンロードしておきます。

まず、分析対象となるサンプルテキストデータを用意します。ここでは、顧客からのフィードバックを想定したリストとします。

feedback_texts = [
    "ログイン機能の使い勝手を改善してほしいです。",
    "もう少し処理速度が速くなると良いと思います。",
    "〇〇機能をぜひ追加してください。",
    "エラーメッセージが分かりにくい点が問題です。",
    "UIデザインをモダンにする提案です。",
    "特に問題なく使えています。",
    "ドキュメントが充実すると助かります。",
    "報告書の自動生成機能があれば便利です。",
    "問い合わせへの応答が遅い。", # これは要望・提案というより問題提起に近い
    "既存の機能には満足しています。"
]

1. キーワード・フレーズマッチングによる抽出

最もシンプルな方法です。特定の単語や固定フレーズが含まれているかを判定します。

keywords = ["改善", "要望", "希望", "〜ほしい", "〜べき", "提案", "追加", "〜が良い", "助かります", "便利です"]

def extract_by_keywords(texts, keywords):
    extracted = []
    for text in texts:
        # いずれかのキーワードが含まれているか確認
        if any(kw in text for kw in keywords):
            extracted.append(text)
    return extracted

print("--- キーワードマッチング ---")
extracted_keywords = extract_by_keywords(feedback_texts, keywords)
for text in extracted_keywords:
    print(f"- {text}")

出力例:

--- キーワードマッチング ---
- ログイン機能の使い勝手を改善してほしいです。
- もう少し処理速度が速くなると良いと思います。
- 〇〇機能をぜひ追加してください。
- UIデザインをモダンにする提案です。
- ドキュメントが充実すると助かります。
- 報告書の自動生成機能があれば便利です。
- 既存の機能には満足しています。 # 「満足しています」が含まれていないが、「既存の機能に」が引っかかる可能性。キーワードリストによる。

この方法は簡単ですが、「既存の機能には満足しています。」のように、要望や提案ではないテキストも誤って抽出する可能性があります。また、「改善」という単語が別の文脈で使用されている場合も区別できません。

2. 正規表現によるパターン抽出

もう少し柔軟性を持たせるために、正規表現を使用します。例えば、「〜を〜してほしい」のような特定の文型パターンを捉えることができます。

import re

# 例: 「[何か] + を/が/の + [改善/追加/変更など] + してほしい/してくれ/希望」のようなパターン
# ここではシンプルな例として、「〜してほしい」「〜が良い」「〜提案」「〜追加」を捕捉するパターンを定義
patterns = [
    r".+てほしい",  # 〜してほしい
    r".+が良い(と思います)?", # 〜が良い(と思います)
    r".+提案(です)?", # 〜提案(です)
    r".+追加(してくださ|希望|要求|があれば)", # 〜追加(してくださる、希望、要求、があれば)
    r".+助かります", # 〜助かります
    r".+便利です" # 〜便利です
]

def extract_by_regex(texts, patterns):
    extracted = []
    for text in texts:
        # いずれかのパターンにマッチするか確認
        if any(re.search(pattern, text) for pattern in patterns):
            extracted.append(text)
    return extracted

print("\n--- 正規表現パターンマッチング ---")
extracted_regex = extract_by_regex(feedback_texts, patterns)
for text in extracted_regex:
    print(f"- {text}")

出力例:

--- 正規表現パターンマッチング ---
- ログイン機能の使い勝手を改善してほしいです。
- もう少し処理速度が速くなると良いと思います。
- 〇〇機能をぜひ追加してください。
- UIデザインをモダンにする提案です。
- ドキュメントが充実すると助かります。
- 報告書の自動生成機能があれば便利です。

正規表現を使うことで、キーワード単体よりも少し複雑な構造を捉えられますが、やはり定義したパターン以外の表現には対応できませんし、誤判定のリスクは残ります。

3. SpaCyを用いたNLPベースの抽出

SpaCyのようなNLPライブラリを利用すると、単語の意味的な役割(品詞)や単語間の構造的な関係(依存関係)を利用して、より精度の高いパターンを定義することが可能になります。

例えば、「(ユーザーが)何かを改善することを求めている」という構造を考えます。日本語では「〜を改善してほしい」のような形が多いですが、これを依存関係で見ると、「改善してほしい」が文のルート(root)や主要な動詞句を形成し、その目的語(dobj)や関連する事柄が「〜を」の部分に来ることが多いです。

ここでは、「改善」「追加」「変更」「要望」「提案」「希望」といった「要望・提案」に関連するキーワード(語彙)が、文中の特定の役割(例:動詞、名詞、サ変動詞)として出現し、かつ、その周辺の単語との依存関係が特定のパターンを満たすものを抽出するアプローチを考えます。

import spacy

# 日本語モデルをロード
# 事前に python -m spacy download ja_core_news_sm を実行してください
try:
    nlp = spacy.load("ja_core_news_sm")
except:
    print("SpaCyモデル 'ja_core_news_sm' が見つかりません。ダウンロードしてください。")
    print("実行コマンド: python -m spacy download ja_core_news_sm")
    exit()


# 要望・提案に関連する語彙リスト(名詞、動詞、サ変動詞など)
request_suggest_lexicon = {
    "NOUN": ["改善", "要望", "提案", "希望", "追加", "変更", "効率化", "簡素化", "強化"],
    "VERB": ["改善する", "追加する", "変更する", "要望する", "提案する", "希望する", "求める"], # サ変動詞はVERBに含まれることが多い
    "AUX": ["ほしい", "やすい", "べき"], # 助動詞や形容詞の一部など
    "ADJ": ["良い", "助かる", "便利"] # 形容詞の一部
}

# 依存関係に基づいたパターン定義の考え方
# 例1:「[何か] を 改善してほしい」 -> 「改善してほしい」がROOTなど、目的語が「何か」
# 例2:「〜が良い」 -> 「良い」がROOTなど
# 例3:「〜追加機能があれば便利」 -> 「追加機能」が名詞、「便利」が形容詞で、何らかの形で関連づいている

def extract_by_spacy(texts, lexicon):
    extracted = []
    for text in texts:
        doc = nlp(text)
        is_request_suggest = False

        # 単純な語彙マッチング(第1段階)
        # 文中に要望・提案関連の語彙が含まれているか
        relevant_tokens = [
            token for token in doc
            if token.lemma_ in lexicon.get(token.pos_, []) or token.text in lexicon.get(token.pos_, [])
        ]

        if relevant_tokens:
            # 語彙が見つかった場合、さらに依存関係や品詞、パターンをチェック
            # ここでは簡単な例として、「〜てほしい」や特定の関連語句+「良い/便利/助かる」
            # あるいは、要望・提案関連の語彙がROOTやその子要素になっているかなどを判定
            for token in doc:
                # 例: 「〜てほしい」のパターンを依存関係で捉える(AUX「ほしい」が特定の動詞の子であるなど)
                if token.lemma_ == "ほしい" and token.pos_ == "AUX":
                     # 「ほしい」が動詞「して」の子であるかなどをチェック
                    if token.head.pos_ == "VERB" or token.head.pos_ == "NOUN" and token.head.tag_ == "名詞,サ変接続":
                        is_request_suggest = True
                        break

                # 例: 「改善」「追加」といった語彙が動詞として使われ、文の主たる述語に近い位置にあるか
                if token.lemma_ in ["改善する", "追加する", "変更する", "要望する", "提案する", "希望する"] and (token.dep_ == "ROOT" or token.dep_ == "acl"):
                     is_request_suggest = True
                     break

                # 例: 「改善」「要望」「提案」といった名詞が、文の主語や目的語に近い位置にあるか
                if token.lemma_ in ["改善", "要望", "提案", "希望", "追加", "変更"] and (token.dep_ == "nsubj" or token.dep_ == "obj" or token.dep_ == "ROOT"):
                     is_request_suggest = True
                     break

                # 例: 「良い」「助かる」「便利」といった形容詞が、文の主語や名詞句に関連づいているか
                if token.lemma_ in ["良い", "助かる", "便利"] and (token.dep_ == "ROOT" or token.dep_ == "acl" or token.dep_ == "nsubj"):
                     # さらに、その形容詞が評価対象(機能、速度など)と関連づいているかなどをチェックすることも可能
                     is_request_suggest = True
                     break

        if is_request_suggest:
            extracted.append(text)

    return extracted

print("\n--- SpaCyによるNLPベース抽出 ---")
# 注意: この例のSpacyパターンは簡易的なものです。実用にはより洗練されたルールや辞書が必要です。
extracted_spacy = extract_by_spacy(feedback_texts, request_suggest_lexicon)
for text in extracted_spacy:
     print(f"- {text}")

出力例(環境やSpaCyモデルバージョンに依存します):

--- SpaCyによるNLPベース抽出 ---
- ログイン機能の使い勝手を改善してほしいです。
- もう少し処理速度が速くなると良いと思います。
- 〇〇機能をぜひ追加してください。
- UIデザインをモダンにする提案です。
- ドキュメントが充実すると助かります。
- 報告書の自動生成機能があれば便利です。

SpaCyを利用することで、単なる単語マッチングでは難しかった、文脈や構造を考慮した抽出が可能になります。上記のコード例はあくまで基本的な考え方を示すものですが、token.pos_(品詞)、token.dep_(依存関係)、token.head(依存関係上の親)などを組み合わせることで、より複雑で精度の高いルールベースの抽出ロジックを構築できます。例えば、特定の動詞の直接目的語が改善対象となっているか、助動詞「たい」や「べき」が主節の動詞にかかっているか、などを詳細に定義することが可能です。

実務への応用と考慮事項

今回ご紹介した手法は、以下のような様々な業務シナリオに応用できます。

これらのタスクにおいて、今回のようなルールベースや辞書ベースのアプローチは、比較的少ないデータで開始でき、抽出理由が明確(どのルールにマッチしたか)であるため、結果の解釈やルールの改善が行いやすいという利点があります。

しかし、実務で利用する際には以下の考慮事項があります。

これらの限界を踏まえ、より高度な抽出が必要な場合は、教師あり学習によるテキスト分類(例:「このテキストは要望である」というラベルを付けて分類器を学習させる)や、特定のエンティティや関係を抽出する機械学習モデルの導入なども検討することになります。しかし、まずは今回のようなルールベースや軽量NLPのアプローチから開始し、必要に応じてステップアップしていくのが現実的な進め方となるでしょう。

まとめ

本記事では、業務テキストから要望や提案といった特定の情報を抽出するために、PythonのreモジュールとspaCyライブラリを活用する具体的な手法を解説しました。キーワード・フレーズマッチング、正規表現によるパターン抽出、そしてNLPによる構造分析といった異なるアプローチを組み合わせることで、多様な表現に対応し、より精度の高い抽出を目指せます。

これらの手法は、顧客の声の分析や業務改善提案の収集など、実務上の様々な課題解決に役立てることが可能です。最初はシンプルなルールから始め、実際のテキストデータで試しながら、徐々にルールを洗練させていくことが成功の鍵となります。

今回ご紹介した内容は、テキストパターンからの情報抽出における基礎的ながらも強力な一歩となります。ぜひ、お手元の業務テキストに適用し、埋もれている価値ある情報を発見してみてください。