Dr.Sum×Amazon Comprehend で実現する感情分析 ~ Python連携機能による実装例

BI技術者の雑記

近年、データを活用した意思決定が求められることを背景に、企業のデータ分析基盤の構築が注目されています。
商品レビューや問い合わせ履歴などのテキストデータには貴重な情報が含まれていますが、その分析には多大な時間と労力が必要です。

本記事では、Dr.SumのPython連携機能とAWSの自然言語処理サービス Amazon Comprehend を組み合わせて、テキストデータから感情を分析する実装方法をご紹介します。

本記事では以下の内容を実装します。

  • Dr.Sumに登録されたテキストデータを取得
  • Amazon Comprehendによる感情分析の実行
  • 分析結果をDr.Sumのテーブルとして表示

これにより、テキストデータの感情分析基盤を構築する方法を学ぶことができます。

1. 連携の仕組み

Python実行環境とDr.Sum Server間のデータの受け渡しは、pandas. DataFrameを介して行われます。

各コンポーネントの役割:

  • Dr.Sum Server:
    データベースとして機能し、Python連携機能を利用
  • Python実行環境:
    Amazon Comprehend APIとの通信を担当(botoライブラリを使用)
  • Amazon Comprehend:
    テキストの感情分析を実施
    POSITIVE/NEGATIVE/NEUTRAL/MIXED の4つの感情スコアを提供

2. サンプルデータとテーブル構成

感情分析用のサンプルデータ「customer_feedback.csv」を用意しました。

ID,日付,カテゴリ,フィードバック
1,"2024-03-01","商品品質","とても満足しています。品質が素晴らしく、期待以上の商品でした。また購入したいと思います。"
2,"2024-03-02","配送","配送が遅すぎます。注文から到着まで2週間もかかり、非常に不便でした。改善を希望します。"
3,"2024-03-03","カスタマーサービス","対応が丁寧で分かりやすかったです。問い合わせへの回答も早く、安心して買い物ができました。"
4,"2024-03-04","商品品質","商品に傷があり、大変がっかりしました。このような品質管理の不備は改善すべきです。"
5,"2024-03-05","価格","値段は少し高めですが、品質を考えると妥当だと思います。"
6,"2024-03-06","使用感","使いやすさは普通です。特に良いところも悪いところもありません。"
7,"2024-03-07","商品品質","素晴らしい商品です!デザインも機能も完璧で、友人にも勧めたいと思います。"
8,"2024-03-08","配送","配送は予定通りでしたが、梱包が少し雑でした。"
9,"2024-03-09","カスタマーサービス","問い合わせの返信が遅く、とても困りました。もう少し迅速な対応を期待します。"
10,"2024-03-10","使用感","思っていたより良かったです。使い心地が良く、毎日楽しく使用しています。"

データの内容:

  • データ項目:
    ・ID:識別子
    ・日付:受付日
    ・カテゴリ:商品品質/配送/カスタマーサービスなど
    ・フィードバック:感情分析対象のテキスト
  • テキストの特徴:
    ・肯定的/否定的/中立的な意見をバランスよく含む
    ・感情表現が明確な日本語の文章

Dr.Sum用のデータベースとテーブル構成:

  • データベース名:SENTIMENT_DEMO
  • テーブル構成:
    ・CUSTOMER_FEEDBACK
     ・ID, 日付, カテゴリ, フィードバック
     ・CSVから一括登録

3. 必要な準備

AWSアカウントの設定

  • AWSアカウントの作成
  • Amazon Comprehend の利用権限設定
  • AWS認証情報の設定(アクセスキー等)

Dr.Sum の Python 連携設定

  • Python連携サービス(Dr.Sum 5.7 Launch Server)の起動
  • インメモリサーバーの設定、インメモリオブジェクトのロード
  • boto3のインストール(AWS SDK for Python)

まず、Python連携用サービス(Dr.Sum 5.7 Launch Server)を起動します。
※Python連携用サービスは、管理サーバーやPython連携機能が起動する処理プロセスを管理するためのサービスです。

次に、インメモリサーバーを設定し、オブジェクトをロードします。
※Python連携機能は、インメモリテーブルやインメモリビューのデータに対して処理をするため、事前にインメモリサーバーの設定が必要です。

対象のテーブルのプロパティ画面で、[インメモリ化する]をオンにします。

次に、インメモリテーブルをロードします。
対象テーブルを選択し、右クリックメニューから[インメモリ] – [データをロード]を選択します。

続いて、クライアント用Python実行環境に、boto3をインストールします。
クライアント用Python実行環境のpython.exe使ってpip installコマンドを実行します。

実行例:

$ /path/to/DrSum57/AdminTools/udtf-python/python/python.exe -m pip install -r data/requirements.txt

Dr.Sum ServerのPython実行環境であるインメモリサーバーに対しては、Python Developer Toolを使用します。

関連ページ▼
https://cs.wingarc.com/manual/drsum/5.7/ja/UUID-fc4390d9-f137-9930-8fca-d130a8281c69.html

以下は、事前に用意したrequirements.txtを指定して、boto3をインストールしています。

4. 実装手順

Pythonスクリプトの作成

Dr.Sumに登録されたテキストデータの感情分析を行うPythonスクリプトを作成します。

処理の流れ:

  • Dr.Sum からテキストデータを取得
  • Amazon Comprehend APIで感情分析を実行
  • 分析結果をテーブルとして表示

作成する2つのPythonファイル:

script/
├── config.py        # Dr.Sumの接続設定
└── comprehend_job.py  # 感情分析の処理

Dr.Sum接続設定(config.py):

# 接続パラメータをタプルとして定義
DS_CONFIG = (
    os.getenv('DRSUM_HOST', 'localhost'),
    int(os.getenv('DRSUM_PORT', '6001')),
    'Administrator',
    '',
    os.getenv('DRSUM_DATABASE', 'SENTIMENT_DEMO')
)

感情分析の処理(comprehend_job.py):

import boto3
import pandas as pd
from dspy.connector import connect

import sys
from pathlib import Path

import boto3
import pandas as pd
from dspy.connector import connect
# モジュール検索パスの設定
sys.path.append(str(Path(__file__).parent))

# ローカルモジュールのインポート
from config import DS_CONFIG

def analyze_sentiment(input):

    # Comprehendクライアントを作成
    session = boto3.Session(profile_name='gen-ai-apps')
    comprehend = session.client(
        "comprehend",
        region_name="us-east-1"
    )
    # 感情分析の結果を格納するリスト
    sentiment_list = []

    # 各レコードに対して感情分析を実施
    for reason in input['フィードバック']:
        if not reason or pd.isna(reason):
            sentiment_list.append(None)
            continue

        # 感情分析実施
        response = comprehend.detect_sentiment(Text=reason, LanguageCode='ja')

        sentiment = response["Sentiment"]
        scores = response["SentimentScore"]

        sentiment_list.append({
            "Sentiment": sentiment,
            "Positive": scores.get("Positive"),
            "Negative": scores.get("Negative"),
            "Neutral": scores.get("Neutral"),
            "Mixed": scores.get("Mixed"),
        })

    output = input[["ID", "フィードバック"]].copy()
    # 結果を新しいカラムとして追加
    sentiment_df = pd.DataFrame(sentiment_list)
    output = pd.concat([output, sentiment_df], axis=1)
    return output

if __name__ == '__main__':
    with connect(*DS_CONFIG) as connection:
        df, col_info_list = connection.preview(
            query='SELECT * FROM CUSTOMER_FEEDBACK;', row_count=10)
        result = analyze_sentiment(df)
        print('----- result -----')
        print(result)

使用している主な機能:


クライアント用Python実行環境で動作確認を行います:

$ /path/to/DrSum57/AdminTools/udtf-python/python/python.exe script/comprehend_job.py

実行結果:

# 入力データ
   ID          日付       カテゴリ                                       フィードバック
0   1  2024-03-01       商品品質  とても満足しています。品質が素晴らしく、期待以上の商品でした。また購入したいと思います。
1   2  2024-03-02         配送   配送が遅すぎます。注文から到着まで2週間もかかり、非常に不便でした。改善を希望します。
2   3  2024-03-03  カスタマーサービス  対応が丁寧で分かりやすかったです。問い合わせへの回答も早く、安心して買い物ができました。
3   4  2024-03-04       商品品質      商品に傷があり、大変がっかりしました。このような品質管理の不備は改善すべきです。
4   5  2024-03-05         価格                   値段は少し高めですが、品質を考えると妥当だと思います。
5   6  2024-03-06        使用感               使いやすさは普通です。特に良いところも悪いところもありません。
6   7  2024-03-07       商品品質          素晴らしい商品です!デザインも機能も完璧で、友人にも勧めたいと思います。
7   8  2024-03-08         配送                        配送は予定通りでしたが、梱包が少し雑でした。
8   9  2024-03-09  カスタマーサービス         問い合わせの返信が遅く、とても困りました。もう少し迅速な対応を期待します。
9  10  2024-03-10        使用感           思っていたより良かったです。使い心地が良く、毎日楽しく使用しています。
----- result -----
   ID                                       フィードバック Sentiment  Positive  Negative   Neutral     Mixed
0   1  とても満足しています。品質が素晴らしく、期待以上の商品でした。また購入したいと思います。  POSITIVE  0.999872  0.000082  0.000030  0.000016
1   2   配送が遅すぎます。注文から到着まで2週間もかかり、非常に不便でした。改善を希望します。  NEGATIVE  0.000040  0.999869  0.000087  0.000004
2   3  対応が丁寧で分かりやすかったです。問い合わせへの回答も早く、安心して買い物ができました。  POSITIVE  0.999729  0.000032  0.000236  0.000003
3   4      商品に傷があり、大変がっかりしました。このような品質管理の不備は改善すべきです。  NEGATIVE  0.000188  0.999738  0.000068  0.000006
4   5                   値段は少し高めですが、品質を考えると妥当だと思います。     MIXED  0.002558  0.000276  0.000067  0.997099
5   6               使いやすさは普通です。特に良いところも悪いところもありません。  POSITIVE  0.995965  0.000882  0.003109  0.000043
6   7          素晴らしい商品です!デザインも機能も完璧で、友人にも勧めたいと思います。  POSITIVE  0.999891  0.000031  0.000070  0.000007
7   8                        配送は予定通りでしたが、梱包が少し雑でした。     MIXED  0.000109  0.003001  0.000021  0.996869
8   9         問い合わせの返信が遅く、とても困りました。もう少し迅速な対応を期待します。  NEGATIVE  0.000075  0.999191  0.000731  0.000002
9  10           思っていたより良かったです。使い心地が良く、毎日楽しく使用しています。  POSITIVE  0.999624  0.000248  0.000029  0.000099

クエリー結果の先頭10件と感情分析結果が出力されました。

SQL実行のための準備 – スキーマ定義の追加

次に、SQL文から実行できるようにPythonのプログラムを修正していきます。

Pythonのプログラムの結果表を受け取る場合、Python連携機能の仕組みでは、SQL文を実行するためにスキーマ情報が必要となるため、結果表スキーマ取得関数をPythonスクリプトに定義しておく必要があります。

結果表スキーマ取得関数とは、pandasのDataFrameのスキーマ情報を受け取り、Pythonのプログラムの処理結果表のスキーマ情報を、Dr.Sum側に返すための関数です。

  1. 結果表スキーマ取得関数のスタブを取得する
  2. 出力されたスタブ関数をPythonプログラムに追記する
  3. 結果表を確認する

エミュレーター機能によるスタブ取得

エミュレーター機能を使って結果表スキーマ取得関数のスタブを生成します。
この機能を使うことで、処理関数の戻り値の内容からスキーマ情報を自動的に取得できます。
なお、生成されたスタブは必要に応じて項目名やデータ型を調整できます。

以下の3箇所を修正してエミュレーターを実行します:

  • エミュレーターでの実行用に関数の引数を追加
  • クエリーの直接実行からエミュレーターを使用した実行に変更
  • エミュレーターの実行モード設定

感情分析の処理(comprehend_job.py):

# エミュレーターでの実行用に関数の引数を追加
# - contextはエミュレーター実行時の環境情報を受け取る
# - 元の関数定義: def analyze_sentiment(input):
def analyze_sentiment(context, input):
if __name__ == '__main__':
    with connect(*DS_CONFIG) as connection:
        # クエリーの直接実行からエミュレーターを使用した実行に変更
        # - connection.preview()の代わりにエミュレーターを使用
        # - analyze_sentiment関数の実行結果からスキーマ情報を取得

        # # 変更前: クエリーの直接実行
        # with connect(*DS_CONFIG) as connection:
        #     df, col_info_list = connection.preview(
        #         query='SELECT * FROM CUSTOMER_FEEDBACK;', row_count=10)
        #     result = analyze_sentiment(df)

        # 変更後: エミュレーターを使用した実行
        cwd = Path(__file__).resolve().parent
        import dspy.emulator
        builder = dspy.emulator.EmulatorBuilder(
            input=connection,  # Dr.Sumデータベースへの接続
            query='SELECT * FROM CUSTOMER_FEEDBACK;',  # エミュレーター用の入力クエリ
            py_script_root=cwd.parent / "script",
            py_data_root=cwd.parent / "data")
        emulator = builder.buildSerial(
            py_file_path='PY_SCRIPT_ROOT/comprehend_job.py',
            func_name='analyze_sentiment',
            schema_func_name='analyze_sentiment_schema',
        )
        # エミュレーターの実行モード設定
        # - create_schema_mode=True : スキーマ取得関数のスタブを生成
        # - create_schema_mode=False: スキーマ定義の動作確認
        result = emulator.execute(create_schema_mode=True)
        print('----- OUTPUT -----')
        print(result)

クライアント用Python実行環境で対象のスクリプトを実行します:

$ /path/to/DrSum57/AdminTools/udtf-python/python/python.exe script/comprehend_job.py

実行結果:

= Warning =
以下のクエリーはインメモリサーバーで実行されませんでした。

     SELECT * FROM CUSTOMER_FEEDBACK;

このPythonスクリプトをデプロイした後は、Python連携用関数の引数inputにはインメモリサーバーで実行できるクエリーまたはオブジェクトが指定される必要があります。

==

以下のスタブ関数をpath\to\sample\udtf-py\script\../script\comprehend_job.pyにコピーしてください。

--------------------------------------------------------------------------------
def analyze_sentiment_schema(input_schema):
    return ['ID INTEGER NOT NULL', 'フィードバック VARCHAR NOT NULL', 'Sentiment VARCHAR NOT NULL', 'Positive NUMERIC NOT NULL', 'Negative NUMERIC NOT NULL', 'Neutral NUMERIC NOT NULL', 'Mixed NUMERIC NOT NULL']
--------------------------------------------------------------------------------

----- OUTPUT -----
   ID                                       フィードバック Sentiment  Positive  Negative   Neutral     Mixed
0   1  とても満足しています。品質が素晴らしく、期待以上の商品でした。また購入したいと思います。  POSITIVE  0.999872  0.000082  0.000030  0.000016
1   2   配送が遅すぎます。注文から到着まで2週間もかかり、非常に不便でした。改善を希望します。  NEGATIVE  0.000040  0.999869  0.000087  0.000004
2   3  対応が丁寧で分かりやすかったです。問い合わせへの回答も早く、安心して買い物ができました。  POSITIVE  0.999729  0.000032  0.000236  0.000003
3   4      商品に傷があり、大変がっかりしました。このような品質管理の不備は改善すべきです。  NEGATIVE  0.000188  0.999738  0.000068  0.000006
4   5                   値段は少し高めですが、品質を考えると妥当だと思います。     MIXED  0.002558  0.000276  0.000067  0.997099
5   6               使いやすさは普通です。特に良いところも悪いところもありません。  POSITIVE  0.995965  0.000882  0.003109  0.000043
6   7          素晴らしい商品です!デザインも機能も完璧で、友人にも勧めたいと思います。  POSITIVE  0.999891  0.000031  0.000070  0.000007
7   8                        配送は予定通りでしたが、梱包が少し雑でした。     MIXED  0.000109  0.003001  0.000021  0.996869
8   9         問い合わせの返信が遅く、とても困りました。もう少し迅速な対応を期待します。  NEGATIVE  0.000075  0.999191  0.000731  0.000002
9  10           思っていたより良かったです。使い心地が良く、毎日楽しく使用しています。  POSITIVE  0.999624  0.000248  0.000029  0.000099
        builder = dspy.emulator.EmulatorBuilder(
            input=connection,  # Dr.Sumデータベースへの接続
            query='SELECT * FROM CUSTOMER_FEEDBACK;',  # エミュレーター用の入力クエリ
            py_script_root=cwd.parent / "script",
            py_data_root=cwd.parent / "data")
        emulator = builder.buildSerial(
            py_file_path='PY_SCRIPT_ROOT/comprehend_job.py',
            func_name='analyze_sentiment',
            schema_func_name='analyze_sentiment_schema',
        )
        # エミュレーターの実行モード設定
        # - create_schema_mode=True : スキーマ取得関数のスタブを生成
        # - create_schema_mode=False: スキーマ定義の動作確認
        result = emulator.execute(create_schema_mode=True)
        print('----- OUTPUT -----')
        print(result)

上記の出力結果には、処理関数の戻り値のpandas.DataFrameから求めた結果表のスキーマ情報(項目名とデータ型)を返す、結果表スキーマ取得関数のスタブが生成されています。

スタブ関数 (結果表スキーマ情報)の追加

エミュレーター機能で取得した結果表スキーマ取得関数のスタブを、処理関数の前に挿入します。

:
# 結果表のスキーマ情報を定義するスタブ関数
# - エミュレーターで生成されたスキーマ定義をそのまま使用
# - カラムの型と制約を指定(INTEGER/VARCHAR/NUMERIC、NOT NULL)
def analyze_sentiment_schema(input_schema):
    return ['ID INTEGER NOT NULL', 'フィードバック VARCHAR NOT NULL', 'Sentiment VARCHAR NOT NULL', 'Positive NUMERIC NOT NULL', 'Negative NUMERIC NOT NULL', 'Neutral NUMERIC NOT NULL', 'Mixed NUMERIC NOT NULL']

def analyze_sentiment(context, input):

    # Comprehendクライアントを作成
    session = boto3.Session(profile_name='gen-ai-apps')
    comprehend = session.client(
        "comprehend",
        region_name="us-east-1"
    )
    # 感情分析の結果を格納するリスト
    sentiment_list = []
    :

結果表スキーマ定義の動作確認

結果表スキーマ定義が正しく機能するか確認するため、エミュレーターを検証モードで実行します。

以下のように、”create_schema_mode”を”False”に設定して実行します:

        # 検証モードでエミュレーターを実行
        # - create_schema_mode=False: スキーマ定義の動作確認
        # result = emulator.execute(create_schema_mode=True)
        result = emulator.execute(create_schema_mode=False)
        print('----- OUTPUT -----')
        print(result)

エミュレーターは以下の内容を自動的に検証します:

  • スキーマ定義と結果表の項目数の一致(カラム数)
  • スキーマ定義と結果表のデータ型の一致(INTEGER/VARCHAR/NUMERIC)

クライアント用Python実行環境で動作確認を行います:

$ /path/to/DrSum57/AdminTools/udtf-python/python/python.exe script/comprehend_job.py

実行結果:

= Warning =
以下のクエリーはインメモリサーバーで実行されませんでした。

     SELECT * FROM CUSTOMER_FEEDBACK;

このPythonスクリプトをデプロイした後は、Python連携用関数の引数inputにはインメモリサーバーで実行できるクエリーまたはオブジェクトが指定される必要があります。

==

----- OUTPUT -----
   ID                                       フィードバック Sentiment  Positive  Negative   Neutral     Mixed
0   1  とても満足しています。品質が素晴らしく、期待以上の商品でした。また購入したいと思います。  POSITIVE  0.999872  0.000082  0.000030  0.000016
1   2   配送が遅すぎます。注文から到着まで2週間もかかり、非常に不便でした。改善を希望します。  NEGATIVE  0.000040  0.999869  0.000087  0.000004
2   3  対応が丁寧で分かりやすかったです。問い合わせへの回答も早く、安心して買い物ができました。  POSITIVE  0.999729  0.000032  0.000236  0.000003
3   4      商品に傷があり、大変がっかりしました。このような品質管理の不備は改善すべきです。  NEGATIVE  0.000188  0.999738  0.000068  0.000006
4   5                   値段は少し高めですが、品質を考えると妥当だと思います。     MIXED  0.002558  0.000276  0.000067  0.997099
5   6               使いやすさは普通です。特に良いところも悪いところもありません。  POSITIVE  0.995965  0.000882  0.003109  0.000043
6   7          素晴らしい商品です!デザインも機能も完璧で、友人にも勧めたいと思います。  POSITIVE  0.999891  0.000031  0.000070  0.000007
7   8                        配送は予定通りでしたが、梱包が少し雑でした。     MIXED  0.000109  0.003001  0.000021  0.996869
8   9         問い合わせの返信が遅く、とても困りました。もう少し迅速な対応を期待します。  NEGATIVE  0.000075  0.999191  0.000731  0.000002
9  10           思っていたより良かったです。使い心地が良く、毎日楽しく使用しています。  POSITIVE  0.999624  0.000248  0.000029  0.000099

エラーが発生せずに終了すれば、PythonのプログラムはDr.Sum Server上にデプロイできる状態となります。

Pythonスクリプトのデプロイ

作成したPythonスクリプトやアクセスするデータをデプロイします。

Python Developer Toolを使用して、作成したPythonスクリプトをDr.Sum Serverにデプロイします。

デプロイ先は以下のフォルダー構成となります:

Python連携ルート(PY_ROOTフォルダー)
├─script/  # Pythonスクリプトの配置先
│  ├─comprehend_job.py  # 感情分析の実行スクリプト
└─data/   # データファイルの配置先

Python Developer Toolを使用してスクリプトをデプロイします:

  1. ファイル操作エリアを開く
  2. 左側(ローカルエリア)で`comprehend_job.py`を選択
  3. 右側(サーバーエリア)のscriptフォルダーにドラッグ&ドロップ

デプロイしたスクリプトは、インメモリサーバーにコピーされて実行されます。

Dr.SumからPythonスクリプトを実行

デプロイしたPythonスクリプトをSQL文から実行します。

前提:

  • Python連携用サービス(Dr.Sum 5.7 Launch Server)が起動されていること
  • インメモリオブジェクトがロードされていること
  • 必要なPythonパッケージがインストールされていること
  • AWSの認証情報が設定されていること

SELECT * FROM udtf::serial_py(
    CUSTOMER_FEEDBACK,                                    -- 入力テーブル
    py_file_path='PY_SCRIPT_ROOT/comprehend_job.py',    -- Pythonスクリプトのパス
    func_name='analyze_sentiment',                       -- 実行する関数名
    schema_func_name='analyze_sentiment_schema'          -- スキーマ取得関数名
) T

SQLパラメータの説明:

  • CUSTOMER_FEEDBACK: 感情分析を行うテキストデータを含むテーブル
  • py_file_path: デプロイしたPythonスクリプトのパス
  • func_name: 感情分析を実行する関数名
  • schema_func_name: 結果表のスキーマを定義する関数名

実行結果:

感情分析の結果がテーブル形式で表示され、各テキストの感情スコアを確認できます。

5. おわりに

本記事では、Dr.SumのPython連携機能とAmazon Comprehendを組み合わせた感情分析の実装方法を紹介しました。

  • Dr.Sum の Python連携機能を使用して外部APIと連携
  • Amazon Comprehendの活用により、テキストデータの感情分析を効率的に実施
  • 分析結果をDr.Sumのテーブルとして表示

本記事で実装した感情分析の結果を活用することで、以下のような分析が可能になります。

  • BIツールと連携した可視化
  • 時系列での感情スコアの推移分析
  • カテゴリ別の満足度比較

Dr.Sum Python連携を活用すれば、機械学習モデルや他のAWSサービスとの連携も可能です。
ぜひ、この仕組みを活用して、データをビジネスに活用してみてください。

Dr.Sumの導入や技術的なご質問がございましたら、システムエグゼにお気軽にご相談ください。
経験豊富な技術者が、お客様のデータ活用をサポートいたします。

BI_banner01.png