はじめまして、新入社員のTHです。
AWSは未経験ですが、ブログを書かせていただくことになりました。
以後よろしくお願いいたします!
この記事でやること
Amazon Comprehendを使用して、文章の感情分析をやってみます。
特別な知識は不要で、Web上で体験してみるだけなら、すぐに実践可能です。
最後に簡単な分析パイプラインを作ってみます。
Amazon Comprehendとは
機械学習を使用してテキストから洞察を見つける自然言語処理 (NLP) サービスです。
キーフレーズ(会話のポイント)を抽出したり、感情分析を行ったりできます。
Amazon Comprehendの特徴:
https://aws.amazon.com/jp/comprehend/features/
使ってみた感想
感情分析でPositive, Negativeに分類できるので、Negativeに分類されたデータから改善点に関する知見を抽出できそうだと思いました。
もっと知りたいと思えるサービスでした。
料金について
Amazon公式ページをご参照ください。
Amazon Comprehendの料金:
https://aws.amazon.com/jp/comprehend/pricing/
やってみよう
AWS Comprehendを実際にコンソール上で動かしてみます。
Amazon Comprehendをコンソールで開く
AWSにログインしたら、Comprehendで検索します。
Launch Amazon Comprehendをクリックします。
Input text欄にある、Built-inを選択して、Input textに分析したい文字列を入力していきましょう。
Built-in: AWSが用意したモデルを使用します
Custom: 自分で用意したモデルを利用します
分析結果 エンティティ
「日本の寿司は世界一!」で分析してみました。
先ほどのInput textの下にある、Insightsに結果が表示されます。
エンティティの抽出結果を見てみます。どうやら「寿司」は抽出できていないみたいですね。
現在、食べ物はエンティティ抽出の対象外みたいです。詳しくは下記をご覧ください。
エンティティの検出: https://docs.aws.amazon.com/ja_jp/comprehend/latest/dg/how-entities.html
分析結果 感情スコア
次に感情分析の結果を見てみましょう。
私としては、ポジティブに書いたつもりです。
Positiveスコアが0.69と最も高く、期待通りですね。
では上記を否定形にするとどうでしょうか。
Negativeスコアが最も高くなりそうですが…
Negativeスコアが0.65と期待通りとなりましたね。
パイプラインの作成
コンソール上で手動で行いましたが、自動で感情値を取得できるようにします。
流れは下記のとおりです。
1. JSONファイルをS3(input用のバケット)にアップロード
2. Lambda関数が起動して、感情値を取得
3. JSONファイルに感情値を追加(追加後、Positiveスコアで降順にします)
4. JSONファイルをS3(output用のバケット)にアップロード
S3の作成
S3で検索して、適当な名前でinput用とoutput用のバケットを用意してください。
※ バケット名は全世界でユニークです。私と同じバケット名はつけられません。
Lambda関数の作成
以下4ステップでLambda関数を用意していきます。
①設計図「s3-get-object-python」から関数を作成
Lambdaで検索して、関数を作成します。
「設計図の使用」を選択して、設計図に「s3-get-object-python」を選択します。
S3トリガーには、用意したバケットを指定してください(input用を選択するようご注意ください)
②アクセス権限の編集(S3とComprehendの権限を追加します)
Lambda関数の作成が終了したら、アクセス権限を追加していきます。
1. 設定タブをクリック
2. サイドメニューよりアクセス権限をクリック
3. ロール名をクリックして、ロールの編集画面に遷移
4. 遷移先で下記ポリシーを選択してアタッチ
・AmazonS3FullAccess
・ComprehendFullAccess
③Lambdaのタイムアウト設定を編集
デフォルト設定だとタイムアウトする可能性があるので、編集しておきます。
1. 設定タブをクリック
2. サイドメニューより一般設定を選択
3. 編集ボタンをクリックして、編集画面に遷移
4. タイムアウトの時間を10秒に変更して保存
④実行コードを用意して、Deploy
import json import urllib.parse import boto3 s3 = boto3.client('s3') comprehend = boto3.client('comprehend') def upload_file(bucket, filename, content): s3_object = boto3.resource('s3').Object(bucket, filename) s3_object.put(Body=(content)) def get_sentiment_score(target): sentiment = comprehend.detect_sentiment(Text=target, LanguageCode='ja') return sentiment.get('SentimentScore') def lambda_handler(event, context): bucket = event['Records'][0]['s3']['bucket']['name'] key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8') try: # トリガーとなったS3イベントのファイル内容を取得 response = s3.get_object(Bucket=bucket, Key=key) body = json.load(response['Body']) # 感情分析の結果を追加 for i in range(len(body)): text = body[i]['text'] body[i].update(get_sentiment_score(text)) # 感情分析の結果をアップロード content = sorted(body, key=lambda x:x['Positive'], reverse=True) # 降順 content = json.dumps(content, ensure_ascii=False) # 出力先のbucketは各自、書き換えてください # 必ず出力用のバケットを指定してください(Input用にアップロードすると、無限ループに陥ります) upload_file("出力用のバケット", key, content) return response['ContentType'] except Exception as e: print(e) print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket)) raise e
実際に動かしてみる
今回使用するデータは、社員の入社時の自己紹介文です。
用意したバケットにJSONファイルをアップロードしてみましょう。
JSONファイル
[ {"text":"まだまだ若輩者なので、ご指導のほど、よろしくお願いいたします。"}, {"text":"これからクロスパワーの一員としてがんばっていきたいと思います。よろしくお願いします。"}, {"text":"色々とご迷惑をおかけするかもしれませんが、日々精進してまいりますので、どうぞよろしくお願いいたします。"}, {"text":"よろしくおねがいします!"}, {"text":"コツコツ頑張ります"}, {"text":"がんばりますので、よろしくお願いいたします。"}, {"text":"ねこと一緒にがんばります。ゲームのマルチプレイのお誘い待ってます!"}, {"text":"仕事になれるまでは、聞く事がたくさんあると思いますが、よろしくおねがいします。"}, {"text":"気軽に話しかけて下さい。"}, {"text":"よろしくお願いします。"}, {"text":"一日でも早く会社に貢献できるようがんばりますので、ご指導よろしくお願いいたします。"}, {"text":"がんばります。よろしくお願いします。"}, {"text":"1日でも早く仕事になじめるようにがんばります。"}, {"text":"初めての事ばかりですが、頑張ります。"}, {"text":"これからよろしくお願い致します。"}, {"text":"仕事を早く覚えるよう精進して参りますので、よろしくお願いいたします。"}, {"text":"未経験でございますが、努力してまいりますので、宜しくお願いします。"}, {"text":"早々にお役に立てるよう頑張ります!"}, {"text":"至らぬ点が多々あると思いますが、よろしくお願い致します。"}, {"text":"色々な事に挑戦したいです。よろしくお願いします。"}, {"text":"よろしくお願いします。"}, {"text":"真面目に楽しく社会人生活を楽しみます!"}, {"text":"一生懸命頑張ります。"}, {"text":"未経験の身ではありますが一生懸命がんばるので、よろしくお願いします!"}, {"text":"宜しくお願いします。"}, {"text":"人として、SEとして成長できるようにがんばります。"}, {"text":"インフラ配属となりました。皆様よろしくお願いします。"}, {"text":"よろしくお願いします。"}, {"text":"これからがんばります。"}, {"text":"何かと抜けていて至らぬ点が多々ありますが、よろしくお願いします。"}, {"text":"早く活躍できるよう努めてまいります。"}, {"text":"お役に立てるよう努めますのでよろしくお願いします。"}, {"text":"早く仕事を覚えて戦力になれるように頑張ります。"}, {"text":"未熟者ですが精一杯がんばります。"}, {"text":"クロスパワーの文化に早く溶け込めるようがんばります。"}, {"text":"頑張ります。"}, {"text":"一生懸命頑張りますので宜しくお願いします!"}, {"text":"宜しくお願いします!"}, {"text":"頑張りますので、宜しくお願いします!"}, {"text":"挑戦をあきらめません。"}, {"text":"すごく入りたかった会社に入社出来て、とてもうれしいです。がんばりますのでよろしくお願いします。肩がこったらいつでも声かけてください^^"}, {"text":"仕事も楽しくをモットーに仕事をしています。休日は大体スノボ、釣りをしているのでお誘いください!"}, {"text":"よろしくお願いします。"} ]
input用のバケットにアップロードしたら、output用のバケットに移動します。
新規ファイルが作成されているはずです。ダウンロードして感情値が追加されているか確認します。
※ Lambda関数の処理が終了していない場合、しばらく待ちます。
ダウンロードしたら結果を見てみましょう。
出力結果
Positiveスコアで結果を降順にしています。
個人的にはどれもポジティブな自己紹介に感じます!
Positiveスコアが低いからといって、Negativeスコアが高いわけではありませんね。
上位にあるものは、個人的な感覚ともマッチしています。
[ {"text": "真面目に楽しく社会人生活を楽しみます!", "Positive": 0.9980524778366089, "Negative": 3.910830128006637e-05, "Neutral": 0.0018935317639261484, "Mixed": 1.483429969084682e-05}, {"text": "すごく入りたかった会社に入社出来て、とてもうれしいです。がんばりますのでよろしくお願いします。肩がこったらいつでも声かけてください^^", "Positive": 0.9973375201225281, "Negative": 7.24554993212223e-05, "Neutral": 0.0025308961048722267, "Mixed": 5.910595064051449e-05}, {"text": "これからよろしくお願い致します。", "Positive": 0.9960934519767761, "Negative": 0.0003147170937154442, "Neutral": 0.00358265801332891, "Mixed": 9.196657629217952e-06}, {"text": "一生懸命頑張りますので宜しくお願いします!", "Positive": 0.9959995746612549, "Negative": 0.00014208932407200336, "Neutral": 0.0038421181961894035, "Mixed": 1.6192951079574414e-05}, {"text": "よろしくおねがいします!", "Positive": 0.9949235320091248, "Negative": 0.000494243809953332, "Neutral": 0.0045768702402710915, "Mixed": 5.342153599485755e-06}, {"text": "頑張りますので、宜しくお願いします!", "Positive": 0.993073046207428, "Negative": 0.00019358166900929064, "Neutral": 0.006719977594912052, "Mixed": 1.3403773664322216e-05}, {"text": "宜しくお願いします!", "Positive": 0.990885317325592, "Negative": 0.0002177592396037653, "Neutral": 0.008888466283679008, "Mixed": 8.483581041218713e-06}, {"text": "仕事も楽しくをモットーに仕事をしています。休日は大体スノボ、釣りをしているのでお誘いください!", "Positive": 0.986234188079834, "Negative": 4.6934408601373434e-05, "Neutral": 0.013689090497791767, "Mixed": 2.988532287417911e-05}, {"text": "早々にお役に立てるよう頑張ります!", "Positive": 0.9791128635406494, "Negative": 0.0005151255172677338, "Neutral": 0.02034587785601616, "Mixed": 2.62462690443499e-05}, {"text": "一日でも早く会社に貢献できるようがんばりますので、ご指導よろしくお願いいたします。", "Positive": 0.9733215570449829, "Negative": 0.0005047339363954961, "Neutral": 0.026163749396800995, "Mixed": 9.974874046747573e-06}, {"text": "挑戦をあきらめません。", "Positive": 0.9646511077880859, "Negative": 0.0016795678529888391, "Neutral": 0.03364716097712517, "Mixed": 2.2128395357867703e-05}, {"text": "お役に立てるよう努めますのでよろしくお願いします。", "Positive": 0.9617434144020081, "Negative": 0.0003617567417677492, "Neutral": 0.03788091987371445, "Mixed": 1.3896367818233557e-05}, {"text": "宜しくお願いします。", "Positive": 0.9595017433166504, "Negative": 0.0003451470984145999, "Neutral": 0.040138497948646545, "Mixed": 1.4592422303394414e-05}, {"text": "まだまだ若輩者なので、ご指導のほど、よろしくお願いいたします。", "Positive": 0.9572271108627319, "Negative": 0.0005388210993260145, "Neutral": 0.04219797998666763, "Mixed": 3.614382148953155e-05}, {"text": "がんばります。よろしくお願いします。", "Positive": 0.9285699129104614, "Negative": 0.004425073508173227, "Neutral": 0.06698764115571976, "Mixed": 1.7277885490329936e-05}, {"text": "よろしくお願いします。", "Positive": 0.9280008673667908, "Negative": 0.002992258407175541, "Neutral": 0.0689290463924408, "Mixed": 7.792825635988265e-05}, {"text": "よろしくお願いします。", "Positive": 0.9280008673667908, "Negative": 0.002992258407175541, "Neutral": 0.0689290463924408, "Mixed": 7.792825635988265e-05}, {"text": "よろしくお願いします。", "Positive": 0.9280008673667908, "Negative": 0.002992258407175541, "Neutral": 0.0689290463924408, "Mixed": 7.792825635988265e-05}, {"text": "よろしくお願いします。", "Positive": 0.9280008673667908, "Negative": 0.002992258407175541, "Neutral": 0.0689290463924408, "Mixed": 7.792825635988265e-05}, {"text": "がんばりますので、よろしくお願いいたします。", "Positive": 0.9153178334236145, "Negative": 0.003962054383009672, "Neutral": 0.08070055395364761, "Mixed": 1.9533901649992913e-05}, {"text": "これからクロスパワーの一員としてがんばっていきたいと思います。よろしくお願いします。", "Positive": 0.8996465802192688, "Negative": 0.002966221421957016, "Neutral": 0.0973653569817543, "Mixed": 2.1831532649230212e-05}, {"text": "仕事になれるまでは、聞く事がたくさんあると思いますが、よろしくおねがいします。", "Positive": 0.8903701305389404, "Negative": 0.0012445531319826841, "Neutral": 0.08261790126562119, "Mixed": 0.025767317041754723}, {"text": "色々な事に挑戦したいです。よろしくお願いします。", "Positive": 0.8853881359100342, "Negative": 0.0008263525669462979, "Neutral": 0.11376026272773743, "Mixed": 2.5274257495766506e-05}, {"text": "色々とご迷惑をおかけするかもしれませんが、日々精進してまいりますので、どうぞよろしくお願いいたします。", "Positive": 0.8642394542694092, "Negative": 0.0010782324243336916, "Neutral": 0.134404718875885, "Mixed": 0.00027757862699218094}, {"text": "インフラ配属となりました。皆様よろしくお願いします。", "Positive": 0.8211432099342346, "Negative": 0.007623747456818819, "Neutral": 0.17120759189128876, "Mixed": 2.5437413569306955e-05}, {"text": "頑張ります。", "Positive": 0.7718032598495483, "Negative": 0.00844748318195343, "Neutral": 0.219117671251297, "Mixed": 0.000631549977697432}, {"text": "早く活躍できるよう努めてまいります。", "Positive": 0.7453831434249878, "Negative": 0.00042650187970139086, "Neutral": 0.25416290760040283, "Mixed": 2.7507385311764665e-05}, {"text": "一生懸命頑張ります。", "Positive": 0.7420463562011719, "Negative": 0.006911689881235361, "Neutral": 0.25069305300712585, "Mixed": 0.0003488249785732478}, {"text": "未経験の身ではありますが一生懸命がんばるので、よろしくお願いします!", "Positive": 0.7360607981681824, "Negative": 0.06259702146053314, "Neutral": 0.19928327202796936, "Mixed": 0.0020589393097907305}, {"text": "これからがんばります。", "Positive": 0.6852964162826538, "Negative": 0.07998844981193542, "Neutral": 0.23464520275592804, "Mixed": 6.99266602168791e-05}, {"text": "初めての事ばかりですが、頑張ります。", "Positive": 0.6545454263687134, "Negative": 0.0029141956474632025, "Neutral": 0.3324032723903656, "Mixed": 0.010137174278497696}, {"text": "未経験でございますが、努力してまいりますので、宜しくお願いします。", "Positive": 0.5879949927330017, "Negative": 0.0018560898024588823, "Neutral": 0.4100433588027954, "Mixed": 0.00010557023051660508}, {"text": "仕事を早く覚えるよう精進して参りますので、よろしくお願いいたします。", "Positive": 0.5061310529708862, "Negative": 0.0011824388056993484, "Neutral": 0.492643803358078, "Mixed": 4.2715069866972044e-05}, {"text": "1日でも早く仕事になじめるようにがんばります。", "Positive": 0.46091514825820923, "Negative": 0.18871335685253143, "Neutral": 0.350151926279068, "Mixed": 0.00021956842101644725}, {"text": "早く仕事を覚えて戦力になれるように頑張ります。", "Positive": 0.4140060842037201, "Negative": 0.010371980257332325, "Neutral": 0.5749410390853882, "Mixed": 0.0006809122860431671}, {"text": "気軽に話しかけて下さい。", "Positive": 0.4125920534133911, "Negative": 0.00223811948671937, "Neutral": 0.5851460695266724, "Mixed": 2.381978447374422e-05}, {"text": "コツコツ頑張ります", "Positive": 0.34744033217430115, "Negative": 0.01964150182902813, "Neutral": 0.6325687170028687, "Mixed": 0.0003494280681479722}, {"text": "ねこと一緒にがんばります。ゲームのマルチプレイのお誘い待ってます!", "Positive": 0.32923588156700134, "Negative": 0.04746706038713455, "Neutral": 0.6232355237007141, "Mixed": 6.151555862743407e-05}, {"text": "至らぬ点が多々あると思いますが、よろしくお願い致します。", "Positive": 0.2274141013622284, "Negative": 0.17051787674427032, "Neutral": 0.5776476263999939, "Mixed": 0.024420343339443207}, {"text": "人として、SEとして成長できるようにがんばります。", "Positive": 0.08758891373872757, "Negative": 0.05022376403212547, "Neutral": 0.8620947599411011, "Mixed": 9.247381967725232e-05}, {"text": "クロスパワーの文化に早く溶け込めるようがんばります。", "Positive": 0.051380474120378494, "Negative": 0.5052165389060974, "Neutral": 0.44321373105049133, "Mixed": 0.00018930257647298276}, {"text": "未熟者ですが精一杯がんばります。", "Positive": 0.04379380866885185, "Negative": 0.06648029386997223, "Neutral": 0.0646212100982666, "Mixed": 0.8251046538352966}, {"text": "何かと抜けていて至らぬ点が多々ありますが、よろしくお願いします。", "Positive": 0.009399283677339554, "Negative": 0.05406167358160019, "Neutral": 0.03602847456932068, "Mixed": 0.9005105495452881} ]
感想
簡単にAmazon Comprehendを紹介しました。
手軽に文章を解析できる、とてもいい機能ですね!
今回は自己紹介文の感情値を取得して、Positiveスコアでソートしてみました。
他にも、下記のような応用ができるのではないでしょうか。
・Negativeスコアの高いグループから改善点に関する知見を得る(ログ、アンケートなど)
・Positive, Negativeに分類し、各グループから改善点に関する知見を得る(ログ、アンケートなど)
・物語のピークを感情値の時系列で見つける
・物語のあらすじの感情値から、感情値でランキングにしてみる
・音楽の歌詞から、感情値でランキングにしてみる
Amazon公式のユースケースは下記に記載があります。
Amazon Comprehend:https://aws.amazon.com/jp/comprehend/
以上です、ぜひみなさんも使ってみてください!