6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AWS Comprehend + Lambda + NewRelicで毎日のツイートの感情分析を可視化してみた

Last updated at Posted at 2022-12-14

概要

AWSのComprehendを使って自分のツイートの感情分析を行い、分析結果の数値をNewRelicに送信してダッシュボードを作ります。

完成図

こんな感じに毎日のツイートのポジティブ・ネガティブを可視化させます。

スクリーンショット 2022-12-14 20.32.52.png

用意するもの

  • NewRelicのライセンスキー
  • Twitter APIのキー
  • Lambda関数

Twitter APIキーの発行やNewRelicの使い方詳細の説明は割愛します。

Lambdaで関数作成

コードの全体像としてはこんな感じです

import tweepy
import boto3
import os
import datetime as dt
import json
import requests

# 環境変数を読みこむ
TWITTER_API_KEY = os.environ["TWITTER_API_KEY"]
TWITTER_API_SECRET = os.environ["TWITTER_API_SECRET"]
TWITTER_BEARER_TOKEN = os.environ["TWITTER_BEARER_TOKEN"]
TWITTER_ACCESS_TOKEN = os.environ["TWITTER_ACCESS_TOKEN"]
TWITTER_ACCESS_SECRET = os.environ["TWITTER_ACCESS_SECRET"]
NEWRELIC_KEY = os.environ["NEWRELIC_KEY"]
NEWRELIC_ENDPOINT = os.environ["NEWRELIC_ENDPOINT"]

# Twitter APIと連携
client = tweepy.Client(bearer_token=TWITTER_BEARER_TOKEN,
                        consumer_key=TWITTER_API_KEY,
                        consumer_secret=TWITTER_API_SECRET,
                        access_token=TWITTER_ACCESS_TOKEN,
                        access_token_secret=TWITTER_ACCESS_SECRET
                    )
                    
comprehend = boto3.client('comprehend')

def get_formatted_datetime(fmt, now):
    return dt.datetime.strftime(now, fmt)
    
def get_sentiment_score(target):
    sentiment = comprehend.detect_sentiment(Text=target, LanguageCode='ja')
    return sentiment.get('SentimentScore')
    
## NewRelicにデータを送信する関数
def post_newrelic(data):
    headers = {"X-Insert-Key": NEWRELIC_KEY}
    res = requests.post(NEWRELIC_ENDPOINT, headers=headers, json=data)
    return res
    
def lambda_handler(event,context):

    # twitterのcreated_atはUTCになってる。JSTで時刻を合わせてやる
    fmt = "%Y-%m-%dT15:00:00Z"
    JST = dt.timezone(dt.timedelta(hours=9), 'JST')
    now = dt.datetime.now(JST)
    start_today = get_formatted_datetime(fmt, now - dt.timedelta(days=1))
    now_formatted = get_formatted_datetime("%Y-%m-%dT%H:%M:%SZ",now)

    user = client.get_me()

    # ツイートを取得する
    tweets = client.get_users_tweets(id = user.data.id,
                                    exclude=("replies"),
                                    start_time=start_today,
                                    end_time=now_formatted
                                    )
    tweets_data = tweets.data

    data = []
    if tweets_data != None:
        for i, tweet in enumerate(tweets_data):
            result = get_sentiment_score(tweet.text)

            score = result['Positive'] - result['Negative']
            label = max(result, key=result.get)
            
            if label == 'Positive':
                label = 'ポジティブ'
            elif label == 'Negative':
                label = 'ネガティブ'
            else:
                label = 'その他'
                
            d = {}
            d["eventType"] = "twitter"
            d["positive_score"] = result['Positive']
            d["negative_score"] = result['Negative']
            d["label"] = label
            d["tweet"] = tweet.text
            data.append(d)
            
		
    return post_newrelic(data)

Comprehend APIで返ってくる値

取得したツイートをComprehend APIに投げると

result = get_sentiment_score(tweet.text)

以下のような値が取れます。

{
  "Text": "ツイート内容", 
  "Positive": 0.xxxxxxx, 
  "Negative": 0.xxxxxxx, 
  "Neutral": 0.xxxxxxx, 
  "Mixed": 0.xxxxxxxx
}

Positive, Negative, Neutral, Mixedの4つの感情スコアが返され、それぞれ1に近いほど大きいスコアとされています。

NewRelicに送信する値を定義

今回は以下4つをパラメータとしてNewRelicに送信します。

ポジティブ指数 (positive_score)
ネガティブ指数 (negative_score)
感情ラベル (label)
ツイート内容 (tweet)

d = {}
d["eventType"] = "twitter"
d["positive_score"] = result['Positive']
d["negative_score"] = result['Negative']
d["label"] = label
d["tweet"] = tweet.text
            

感情ラベル(label)は、
Positiveのスコアが最も高得点なツイートを 「ポジティブ」
Negativeのスコアが最も高得点なツイートを 「ネガティブ」
それ以外を 「その他」 として設定します。

label = max(result, key=result.get)
            
if label == 'Positive':
    label = 'ポジティブ'
elif label == 'Negative':
    label = 'ネガティブ'
else:
    label = 'その他'

EventBridgeの設定

作成したLambda関数を毎日呼び出すトリガーをEventBridgeで作成します。

Lambda関数のページからトリガーを追加
スクリーンショット 2022-12-14 20.59.03.png

トリガーの種類としてEventBridgeを選択
スクリーンショット 2022-12-14 20.56.15.png

今回は 「毎日21時に実行する」 ルールを設定します
スクリーンショット 2022-12-14 20.58.49.png

これでEventBridgeの設定は完了です。

NewRelicでグラフを作成

NRQLを使って分析結果をいい感じに表示させるグラフを作成します

直近1週間のツイートのポジティブ指数・ネガティブ指数

SELECT average(positive_score) as 'ポジティブ指数', average(negative_score) as 'ネガティブ指数' FROM twitter since 1 week ago

スクリーンショット 2022-12-14 20.18.49.png

1日ごとのポジティブツイート/ネガティブツイートの数

SELECT count(tweet) FROM twitter where label != 'その他' facet label since 2 week ago TIMESERIES 1 day

スクリーンショット 2022-12-14 20.33.01.png

1週間のポジティブ/ネガティブツイートの比率

SELECT count(*) FROM twitter where label != 'その他' facet label since 1 week ago

スクリーンショット 2022-12-14 20.19.32.png

ツイートごとの分析結果を表示

SELECT label, positive_score , negative_score, tweet FROM twitter since 1 day ago order by timestamp desc

スクリーンショット 2022-12-14 20.40.03.png

所感

  • ネガティブなツイートが多かったらAPI経由で自動でツイ消しのような仕組みも作りたい
    • NewRelicのAlert Condition + Workflowを使用すれば作れそう
  • 割とネガティブっぽいツイートが多いことに気づく
    • 前向きに生きよう!

参考・関連記事

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?