Amazon Comprehend を利用して、Twitter からエゴサーチ #reinvent

ども、藤本です。

AWS re:Invent 2017 にて自然言語処理(Natural Language Processing)サービスの Amazon Comprehend がリリースされました。Amazon Comprehend に関しては下記エントリにまとめてみました。

自然言語処理サービスの Amazon Comprehend についてまとめてみた #reinvent

使ってみて何かスゴいな、という印象は受けるのですが、じゃあ実際に何ができるのでしょうか?ユースケースを考えてみて実装してみました。

概要

Amazon Coprehend はドキュメントから様々な情報を検出することができます。その一つの検出機能に感情の検出があります。感情の検出はPositiveNegativeNeutralMixedという 4つの指標からドキュメントに含まれる感情の検出、およびスコアリングを行ってくれます。この感情の検出を利用して、Twitter のツイートからエゴサーチしてみましょう。

ハッシュタグ#reinventで検索した直近10,000件のツイートを抽出し、それぞれ感情の検出を行い、トータルの件数、パーセンテージの算出、および最もポジティブ、ネガティブと判断されたツイートを抽出します。

簡単に図示すると↓のようなイメージ。

エゴサーチしてみた

環境

  • 端末:Macbook
  • 言語:Python
  • Python:3.6.1
  • Boto3:1.4.8
  • Botocore:1.8.6
  • Twitter SDK:python-twitter

ソースコード

ササッと書いたソースコードを Gist に添付しました。ブログ最下部にソースコードを張り付けています。

実行

2017/12/02 23:20頃の結果です。

1
2
3
4
5
6
7
8
$ time ./sentiment.py
Positive :  993件 : 14.0%
Negative :   22件 : 2.0%
Mixed    :    7件 : 1.0%
Neutral  : 8021件 : 84.0%
Most positive tweet is "#reInvent 2017 was an amazingly marvelous experience!! A huge thank you to @awscloud for all the awesomeness!!"
Most negative tweet is "xxxxxxxxxxxxxxxxxxxxxxx"
./sentiment.py  7.02s user 0.62s system 3% cpu 3:42.37 total

Neutral が多いのはしょうがないですが、うん、Negative に比べて、Positive なツイートが圧倒的に多いですね!re:Invent 素晴らしい!行ったことないけど。最も Positive なツイートは限りなく Positive ですね!実装しておいてなんですが、最も Negative なツイートはマスキング。

まとめ

いかがでしたでしょうか? Twitter API も簡単ですし、Amazon Comprehend の API も前回のエントリでまとめた通り簡単に扱うことができ、簡単に実装することができました。是非、日本語対応した際には弊社のブログや、会社名でエゴサーチしてみたいですね笑

ソースコード

#!/usr/bin/env python
import twitter
import boto3
import os
keyword = '#reinvent'
lang = 'en'
region = 'us-east-1'
size = 100 * 100
def get_tweet_texts():
api = twitter.Api(consumer_key=os.environ['consumer_key'],
consumer_secret=os.environ['consumer_secret'],
access_token_key=os.environ['access_token_key'],
access_token_secret=os.environ['access_token_secret'],
sleep_on_rate_limit=True)
maxid = None
corpus = []
for i in range(int(size/100)):
results = api.GetSearch(term=keyword,result_type='recent',count=100,max_id=maxid,lang=lang)
maxid = min([result.id for result in results]) - 1
corpus.extend(results)
return corpus
def detect_sentiment(corpus):
result = {
'Mixed': 0,
'Negative': 0,
'Neutral': 0,
'Positive': 0,
'MIXED': 0,
'NEGATIVE': 0,
'NEUTRAL': 0,
'POSITIVE': 0,
'MOST_NEGATIVE': {'score':0},
'MOST_POSITIVE': {'score':0},
}
comprehend = boto3.client('comprehend', region_name=region)
batch_size = 25
for tweets in [corpus[i:i+batch_size] for i in range(0, len(corpus), batch_size)]:
sentiment_results = comprehend.batch_detect_sentiment(
TextList=[tweet.text for tweet in tweets],
LanguageCode=lang
)
for sentiment in sentiment_results['ResultList']:
result[sentiment['Sentiment']] += 1
if sentiment['Sentiment'] == 'NEGATIVE' and sentiment['SentimentScore']['Negative'] > result['MOST_NEGATIVE']['score']:
result['MOST_NEGATIVE'] = {'score': sentiment['SentimentScore']['Negative'], 'tweet': tweets[sentiment['Index']]}
elif sentiment['Sentiment'] == 'POSITIVE' and sentiment['SentimentScore']['Positive'] > result['MOST_POSITIVE']['score']:
result['MOST_POSITIVE'] = {'score': sentiment['SentimentScore']['Positive'], 'tweet': tweets[sentiment['Index']]}
for key, score in sentiment['SentimentScore'].items():
result[key] += score
return result
def stdout(result):
sum_score = sum([value for key, value in result.items() if key in ('Mixed', 'Negative', 'Neutral', 'Positive')])
print('Positive : {:4d}件 : {:.1f}%'.format(result['POSITIVE'], round(result['Positive']/sum_score*100), 1))
print('Negative : {:4d}件 : {:.1f}%'.format(result['NEGATIVE'], round(result['Negative']/sum_score*100), 1))
print('Mixed : {:4d}件 : {:.1f}%'.format(result['MIXED'], round(result['Mixed']/sum_score*100), 1))
print('Neutral : {:4d}件 : {:.1f}%'.format(result['NEUTRAL'], round(result['Neutral']/sum_score*100), 1))
if result['MOST_POSITIVE'].get('tweet'):
print('Most positive tweet is "{}"'.format(result['MOST_POSITIVE']['tweet'].text))
if result['MOST_NEGATIVE'].get('tweet'):
print('Most negative tweet is "{}"'.format(result['MOST_NEGATIVE']['tweet'].text))
def main():
corpus = get_tweet_texts()
result = detect_sentiment(corpus)
stdout(result)
if __name__ == '__main__':
main()