📊

Amazon Comprehend(機械学習)で感情分析してみた!

2023/01/06に公開

バヅクリ株式会社CTOの合原です。

久々にAWSのサービスを触る機会があったので、まとめたいと思います。

背景

弊社では、オンラインをベースとして、社内イベントなどを行っているのですが、イベント実施時に参加者にアンケートをとっています。

その中には、選択式の設問もある一方、自由記述式の設問もあります。

このアンケート結果は、実際の参加者の声であり、非常に重要なインサイトデータとなります。

課題

選択式の設問は事前に配点をすることで、定量データとして、
結果の分析がしやすいのですが、

一方、自由記述式の回答については、これまで定性的な判断でしかデータ利用ができていませんでした。
端的に言うと、下記の点がネックになっていました。

  • データ量も少なくなく、精査するのも手間
  • アンケート結果を見る人の解釈が入ってしまう

対策

自由記述式回答結果を定量できないか?と。
そこで、かねてより使ってみたかったAWS Amazon Comprehend(機械学習)を使って見ようと。

Amazon Comprehend自体は、自然言語処理、つまりテキストベースでの分析を行っています。
詳細については下記参照。
https://docs.aws.amazon.com/ja_jp/comprehend/latest/dg/what-is.html
https://aws.amazon.com/jp/builders-flash/202107/awsgeek-comprehend/?awsf.filter-name=*all

やったこと

AWS::Comprehend検証

バヅクリでは、日頃からAWSのサービスを利用しているので、迷わず、Amazon Comprehendを利用できないか検討しました。

幸い、Amazon Comprehendでは、GUIでの、テスト環境があるので、使ってみました。

とりあえず、平易な文で試してみましたところ、👆の通り、
日本語でも、問題なさそう。
...と言うことで、

設計

バヅクリでは、サーバーサイドは、Railsアプリケーションで動かしています。
また、すでにS3など、他のサービスも利用していることから、SDKを利用してサクッと実装することにしました。

gem 'aws-sdk'
https://aws.amazon.com/jp/sdk-for-ruby/

すでに、これまでのAWSサービスを利用する部分については、
下記のように、切り分けていたので、今回は、
新しく下記の構成で、modelを追加してみました。

$ tree -N -d -L 1 app/models/aws

app/models/aws
├── comprehend # これを追加
└── s3

実装

class Aws::Comprehend::Manager
  class ComprehendArgumentError < StandardError; end
  include ActiveModel::Model

  ATTRS = %i[
    detected_text
  ]

  ATTRS.each { |attr| attr_accessor attr }

  def analyze_sentiment
    return raise ComprehendArgumentError, "Not found detected_text" if detected_text.blank?

    client.detect_sentiment(
      text: detected_text, # required
      language_code: "ja",
    )
  end

  def resource
    @resource ||= Aws::Comprehend::Resource.new(region: region)
  end

  private

    def client
      @client ||= resource.client
    end

    def region
      Rails.application.credentials.aws[:region]
    end
end

特に凝ったことはせず、シンプルにSDK経由でAWS Comprehend APIへ分析対象テキストを渡しているだけです。

あとは、これを、バッチなり、必要な箇所で呼び出してあげれば、スコアリングができます。

rake taskにしてみた

今回は、適当なテーブルを用意して、Amazon Comprehendの結果をそのままテーブルに入れます。

※弊社の場合、サービスAPP側のテーブル群を、データ分析のできる環境に定期実行で、そのままコピーしているため、redashでもデータが閲覧できるようになります。

ということで、

namespace :analyze_questionnaire do

  desc 'all of questionnaires analyzes'
  task analyzes: :setup_logger do
    Rake::Task['analyze_questionnaire:analyze:participant_questionnaire'].execute
    :
  end

  namespace :analyze do
    desc 'analyze_participant_questionnaire'
    task participant_questionnaire: :setup_logger do
      include SentimentAnalyzeHelper

      # スコアリングしたいattribute
      free_answers = %i[
        satisfaction_level_reason
        new_awareness
        interactive_points
        event_improve_point
      ]
      # 数が多いので並列化
      Parallel.each(questionnaires, in_threads: thread_number) do |q|
        ActiveRecord::Base.connection_pool.with_connection do
          update_params = free_answers.each_with_object({}) do |attr, h|
                            value = q.send(attr)
                            next if value.blank?
                            next if q.send("sentiment_#{attr}").present?

                            result = sentiment_analyzer(value)
                                                         
						
	                                         # とりあえず、AWS Comprehendの結果をそのまま入れる前提
                            h.merge!(
                              "sentiment_#{attr}": result.sentiment,
                              "sentiment_score_positive_#{attr.to_s}": result.sentiment_score.positive,
                              "sentiment_score_negative_#{attr.to_s}": result.sentiment_score.negative,
                              "sentiment_score_neutral_#{attr.to_s}": result.sentiment_score.neutral,
                              "sentiment_score_mixed_#{attr.to_s}": result.sentiment_score.mixed,
                            )
                          end
          q.assign_attributes(update_params)
          q.save(validate: false)
        end
      end
    end

         :

  end

  private

  task setup_logger: :environment do
    Rails.logger = Logger.new(STDOUT)
  end

  module SentimentAnalyzeHelper
    def questionnaires
      @questionnaires ||= ::Events::ParticipantQuestionnaire.merge(::Events::ParticipantQuestionnaire.where.not(satisfaction_level_reason: "").or(::Events::ParticipantQuestionnaire.where.not(new_awareness: "")).or(::Events::ParticipantQuestionnaire.where.not(interactive_points: "").or(::Events::ParticipantQuestionnaire.where.not(event_improve_point: ""))))
    end

    def sentiment_analyzer(detected_text)
      return {} if !detected_text
 
      # 前述で作ったmodelを使う
      Aws::Comprehend::Manager.new(detected_text: detected_text).analyze_sentiment
    end

    def thread_number
      4
    end
  end
end

あとは、下記を

$ rake analyze_questionnaire:analyzes

定期実行して、

無事、自由記述回答結果の定量化ができました ⭐️

まとめ

初めてAmazon Comprehendを導入してみましたが、AWS SDKで諸々、用意されているので、
導入のハードルも低く、さすがAWSですね。

肝心のデータ自体の詳細な精査はやっていく必要ありそうですが、
こんなに簡単に機械学習を導入できる、というのもありがたい限り。

まだまだ利用していないAWSサービスはたくさんあるので、
どんどん使っていきたいと思います。

恒例のですが。。。

そんなバヅクリでは、現在Railsエンジニアを募集しております!

気になる方はぜひ👇より!

https://herp.careers/v1/buzzkuri/wCQFGVkQS3Xa

https://buzzkuri.co.jp/recruit

こちらにコメントでもいいので、カジュアルにご連絡いただけたらな、と思います!

https://note.com/kieaiaarh

バヅクリテックブログ

Discussion