[Docker, Python] Twitterアナリティクスを分析してみた(④数値分析編)

前回から、Dockerで環境構築、jupyterlabおよびPythonを使用して、Twitter機能の一つであるTwitterアナリティクスのデータを分析しています。

今回から、趣旨である自身のTwitterデータのグラフから、どんなTweetが数値的に人気があったのか調べていきます。

本記事を読むと、

  • 自身のTweetで高評価なものがわかる
  • 高評価Tweetを参考にして、次のTweet内容に生かせる(かも)
  • 分析用のサンプルコード(Python)を使用できる

ので、ので、ぜひ最後までご覧いただけると幸いです。

なお、サンプルコードは最後に記載していますので、サンプルコードだけほしい方は、目次リンクで飛んでみてください。それではやっていましょう!

1. 解析用データの準備

環境構築、マルチインデックス化によるグラフ用Twitterデータの準備が終わってない方は、下記記事をご参考いただけると幸いです。

 時系列のマルチインデックス化は、時間軸を用いるグラフ化には便利な機能です。ぜひ、ご参考いただけると幸いです。

以下の本記事内容は、Docker環境で構築したJupyterlabをベースに作成しています。予めご了承ください。

使用環境概要は以下となります。

  • ホストOS: Windows10 Pro
  • Docker image: ubuntu:18.04
  • Anaconda: Anaconda3-2020.07-Linux-x86_64
  • Python: Version 3.8.3 (64bit)

ファイルフォルダー構成は以下です。

.
|-- docker-compose.yml
`-- python_app
    |-- Dockerfile
    `-- jupyter_work
        |-- Twitter_analytics.ipynb
        |-- data
        |   `-- tweet_activity_metrics_UserName_YYYYMMDD_YYYYMMDD_ja.csv
        |-- data_base_analytics.py
        |-- evaluation_analytics.py
        |-- graph_analytics.py
        `-- time_analytics.py

Dockerfileは以下のようにして、AnacondaをDockerコンテナ内に用意します。

#Dockerfile
FROM ubuntu:18.04
RUN apt-get update && apt-get install -y \
    sudo \
    wget \
    vim

#Anacondaのインストール
WORKDIR /opt
RUN wget https://repo.continuum.io/archive/Anaconda3-2020.07-Linux-x86_64.sh && \
    sh /opt/Anaconda3-2020.07-Linux-x86_64.sh -b -p /opt/anaconda3 && \
    rm -f Anaconda3-2020.07-Linux-x86_64.sh
ENV PATH /opt/anaconda3/bin:$PATH
WORKDIR /
CMD ["jupyter", "lab", "--ip=0.0.0.0", "--allow-root", "--LabApp.token=''"]

また、docker-compose.ymlは以下のようにしています。

#docker-compose.yml

version: '3'

services:
  app:
    build:
      context: ./python_app
      dockerfile: Dockerfile
    container_name: app
    ports:
        - '5551:8888'
    volumes:
      - '.:/work'
    tty: true
    stdin_open: true

2. ‘Engagement’データを視覚的に確認する

 今回は、前回作成したTweetごとの傾向、特に’Engagement’を確認していきます。まずは、以下のコードを入力してみてください。

""" Twitter_analytics.ipynb """
import graph_analytics as ga

""" 4.データ分析編 """
ga.bar_hist_single(twitter_df, 'Engagement')
""" graph_analytics.py """

import matplotlib.pyplot as plt

def bar_hist_single(df, column='Engagement'):
    fig, axes = plt.subplots(2, 1, figsize=(20,8))
    axes[0].bar(df.index, column, data=df, label=column)
    axes[0].set_title(column)
    axes[0].twinx().plot(df.index, 'Engagement_Ratio', color='r', data=df, linestyle='--', marker='o')
    axes[1].hist(column, data=df, label=column, bins=50)
    axes[1].set_xlabel(column)
    axes[1].set_title('Histogram')
    plt.plot()

上記コードを入力すると、axes[0]にTwitterデータのTweetごとの’Engagement’の棒グラフと’Engagement_Ratio’の折れ線グラフ、axes[1]に’Engagement’のヒストグラムが作成されます。

図1. ‘Engagement’の棒グラフと’Engagement_Ratio’の折れ線グラフ

グラフを見ると、多くのTweetは’Engagement’数は低いですが、一部のTweetは’Engagement’数が高くなっています。

次に、’Engagement’の構成要素である[“RT”, “Return”, “Good”, “User_Click”, “URL_Click”, “Hash_Click”, “Detail_Click”]の各月ごとの合計数を見てみます。

以下のコードを入力してみてください。

""" Twitter_analytics.ipynb """

twitter_df_engagement = m_twitter_df.iloc[:, 4:]
ga.bar_bottom_column(twitter_df_engagement, 0.5)
def bar_bottom_column(df, width=0.5):
    bottom = 0
    fig, axes = plt.subplots(1, 1, figsize=(20,5))
    for i in range(len(df)):
        axes.bar(df.columns, df.iloc[i], bottom=bottom, width=width)
        bottom += df.iloc[i]
    axes.set_xlabel('Item')
    axes.set_title('Count')
    axes.legend(df.index)
    fig.tight_layout()
    plt.plot()

以上のコードを入力すると、Twitterデータの月ごとの’Engagement’の構成要素の積み上げ棒グラフが作成されます。

図2. 月ごとの’Engagement’の構成要素の積み上げ棒グラフ

このグラフを見ると、[“Good”, “User_Click”, “Detail_Click”]が’Engagement’数に大きく影響してそうです。各項目の相関関係はどの様になっているでしょうか、確認してみましょう。

なお、相関係数に関しては以下をご参考するとわかりやすいと思います。

相関係数とは何か。その求め方・公式・使い方と3つの注意点

相関関数を確認するため、以下のコードを入力してみましょう。

import evaluation_analytics as ea

ea.corr_df(twitter_df)
""" evaluation_analytics.py """

def corr_df(df):
    fig, axes = plt.subplots(figsize=(20,5))
    df_corr = df.corr()
    sns.heatmap(df_corr, cmap='coolwarm', annot=True, annot_kws={'size': 12}, fmt='.2f')

以上のコードを入力すると、各項目の相関関数が表示されます。

図3. 各項目の相関関数

相関関数がよくわからない方は、こちらのブログが非常にわかりやすいかなともいます。

Pythonで学ぶ】相関係数をわかりやすく解説【データサイエンス入門:統計編11】

相関係数を見ると、’Engagement’は[“User_Click”, “Detail_Click”]との相関が強そう(1に近い)ですね。一方、”Good”は相関関数が0.5なのでそこまで、’Engagement’に影響しているとは言いづらそうです。

以上から、私のTweetで’Engagement’を増やすには、[“User_Click”, “Detail_Click”]を多く得ているTweetを参考にすると良さそうです。

3. 特定項目の値が上位であるTweetを取得する

[“User_Click”, “Detail_Click”]を多く得ているTweetを抽出するために、以下のコードを入力してみます。

dict_analytics = {'User_Click': 'eval_user', 'Detail_Click': 'eval_detail'}
percent = 10
for col, eva in dict_analytics.items():
    twitter_df = ea.evaluation_percent(twitter_df, column=col, evaluation=eva, percent=percent)
""" evaluation_analytics.py """

def evaluation_percent(df, column='Engagement', evaluation='evaluation', percent=50):
    per = df[column].quantile(q=[(100-percent)/100]).iloc[0]
    df[evaluation] = df[column].apply(lambda x: 'Top{}%'.format(percent) if x >= per else 'Less{}%'.format(percent))
    return df

percent=10は上位何%のTweetを取得するかを決定できます。今回は上位10%を対象としました。

上記のコードで、特定項目(今回は”User_Click”と”Detail_Click”)の上位10%とその他を評価する新たなデータフレームを作成します。

twitter_dfを見てみましょう。以下のように’eval_user’と’eval_detail’のカラムが増えていると思います。なお、’Top10%’が各項目上位10%のTweet、それ以外は’Less10%’と表示するようにしています。

図4. ‘eval_user’と’eval_detail’のカラム

では、’eval_user’と’eval_detail’の評価基準を用いて、”User_Click”と”Detail_Click”がともに上位10%であるTweetを抽出していきます。

以下のコードを入力してみてください。各項目の’Top10%’であるTweetのみを抽出します。

great_twitter_df = twitter_df[(twitter_df['eval_user'] =='Top{}%'.format(percent)) & \
                            (twitter_df['eval_detail'] =='Top{}%'.format(percent))]

great_twitter_dfは、”User_Click”と”Detail_Click”がともに上位10%であるTweetデータとなります。

great_twitter_dfに記載されているTweetを参考にすると、’Engagement’を多く得られる可能性が高いと考えられます。

以上が数値から見た高評価Tweetを抽出する方法のひとつとなります。

4. サンプルコードとまとめ

以上の内容のサンプルコードをまとめたものは以下となります。

ファイルフォルダー構成は以下です。

.
|-- Twitter_analytics.ipynb
|-- data
|   `-- tweet_activity_metrics_BaranGizagiza_YYYYMMDD_YYYYMMDD_ja.csv
|-- data_base_analytics.py
|-- graph_analytics.py
|-- evaluation_analytics.py
`-- time_analytics.py

各ファイルは以下となります。

""" Twitter_analytics.ipynb """

import data_base_analytics as da
import time_analytics as ta
import graph_analytics as ga
import evaluation_analytics as ea

percent = 10

def main():
    """ main """
    """1.準備編 """
    twitter_data_path = da.data_path()
    twitter_df = da.data_df(twitter_data_path)
    twitter_df = da.data_en(twitter_df)
    twitter_df = da.data_time(twitter_df)

    """ 2.時系列編 """
    yqmwwd_twitter_df = ta.yqmwwd_df(twitter_df)
    w_twitter_df = ta.groupby_df(yqmwwd_twitter_df, 'week', 'sum')
    w_twitter_df['Engagement_Ratio'] = ta.engagement_ratio(w_twitter_df)
    m_twitter_df = ta.groupby_df(yqmwwd_twitter_df, 'month', 'sum')
    m_twitter_df['Engagement_Ratio'] = ta.engagement_ratio(m_twitter_df)

    """ 3.グラフ化編 """
    columns = twitter_df.columns.to_list()
    ga.bar_plot(w_twitter_df, columns)

    """ 4.数値分析編 """
    ga.bar_hist_single(twitter_df, 'Engagement')
    ga.bar_bottom_column(m_twitter_df.iloc[:, 3:], 0.5)
    ea.corr_df(twitter_df)

    dict_analytics = {'User_Click': 'eval_user', 'Detail_Click': 'eval_detail'}
    for col, eva in dict_analytics.items():
        twitter_df = ea.evaluation_percent(twitter_df, column=col, evaluation=eva, percent=percent)
    great_twitter_df = twitter_df[(twitter_df['eval_user'] =='Top{}%'.format(percent)) & \
                                (twitter_df['eval_detail'] =='Top{}%'.format(percent))]
""" data_base_analytics.py """
"""1.準備編 """

from pathlib import Path
import pandas as pd

Data_path = './data'
Data_file_name = '*ja.csv'
Encode = 'CP932'

def data_path():
    return Path(Data_path ).glob(Data_file_name)

def data_df(file_path):
    LIST = [pd.read_csv(file, encoding=Encode) for file in file_path]
    df = pd.concat(LIST)
    return df

def data_en(df):
    df = df[["ツイート本文","時間","インプレッション",\
             "エンゲージメント","エンゲージメント率","リツイート", \
             "返信","いいね","ユーザープロフィールクリック",\
             "URLクリック数","ハッシュタグクリック","詳細クリック"]]
    df.columns = ["Tweet", "Time", "Impression", "Engagement", \
                  "Engagement_Ratio", "RT", "Return", "Good", "User_Click", \
                  "URL_Click", "Hash_Click", "Detail_Click"]
    return df

def data_time(df):
    df['Time'] = pd.to_datetime(df['Time'].apply(lambda x: x[:-5]))
    df = df.set_index('Time').sort_index()
    return df
""" time_analytics.py """
""" 2.時系列編 """

import datetime

def yqmwwd_df(df):
    yqmwwd_df = df.set_index([df.index.year, df.index.quarter,\
                              df.index.month, df.index.week,\
                              df.index.weekday, df.index.day, df.index])
    yqmwwd_df.index.names = ['year', 'quarter', 'month', 'week', 'weekday', 'day', 'date']
    return yqmwwd_df

def groupby_df(df, level_time='week', agg_iterable='sum'):
    groupby_df = df.groupby(level=level_time).agg(agg_iterable)
    return groupby_df

def engagement_ratio(df):
    return df['Engagement'] / df['Impression']
""" graph_analytics.py """
""" 3.グラフ化編 """

import matplotlib.colors as mcolors
import matplotlib.pyplot as plt

Colors = mcolors.TABLEAU_COLORS.items()

def bar_plot_multi(df, columns):
    fig, axes = plt.subplots(10, 1, figsize=(15,30))
    for idx, (color, rgb) in enumerate(Colors):
        axes[idx].bar(df.index, columns[idx+1], color=rgb, data=df, label=columns[idx+1])
        axes[idx].set_xlabel('Time')
        axes[idx].set_ylabel(columns[idx+1])
        axes[idx].set_title(columns[idx+1])

    fig.tight_layout()
    plt.plot()

""" 4.数値分析編 """
def bar_hist_single(df, column='Engagement'):
    fig, axes = plt.subplots(2, 1, figsize=(20,8))
    axes[0].bar(df.index, column, data=df, label=column)
    axes[0].set_title(column)
    axes[0].twinx().plot(df.index, 'Engagement_Ratio', color='r', data=df, linestyle='--', marker='o')
    axes[1].hist(column, data=df, label=column, bins=50)
    axes[1].set_xlabel(column)
    axes[1].set_title('Histogram')
    plt.plot()

def bar_bottom_column(df, width=0.5):
    bottom = 0
    fig, axes = plt.subplots(1, 1, figsize=(20,5))
    for i in range(len(df)):
        axes.bar(df.columns, df.iloc[i], bottom=bottom, width=width)
        bottom += df.iloc[i]
    axes.set_xlabel('Item')
    axes.set_title('Count')
    axes.legend(df.index)
    fig.tight_layout()
    plt.plot()
""" evaluation_analytics.py """
""" 4.数値分析編 """

import matplotlib.pyplot as plt
import seaborn as sns

def evaluation_percent(df, column='Engagement', evaluation='evaluation', percent=50):
    per = df[column].quantile(q=[(100-percent)/100]).iloc[0]
    df[evaluation] = df[column].apply(lambda x: 'Top{}%'.format(percent) if x >= per else 'Less{}%'.format(percent))
    return df

def corr_df(df):
    fig, axes = plt.subplots(figsize=(20,5))
    df_corr = df.corr()
    sns.heatmap(df_corr, cmap='coolwarm', annot=True, annot_kws={'size': 12}, fmt='.2f')

以上のファイルを用意して、jupyterlab上でmain()を呼び出した後に、great_twitter_dfを呼び出せば、高評価Tweetを抽出できると思います。

私も詰まったところが、pythonファイルを更新すると、モジュールを読み込む際は、「カーネルを再起動するか、import libを使う」必要があります。詳しくは以下のサイトに記載されているので、ご参考いただけると幸いです。

【Python】Jupyter notebookを使うときに守るべきPythonの作法2選

次回は、評価でグラフを分類する手法を用いて、詳細な解析をしていく予定です。

また、今後の分析内容としては

  • MySQLとの連携
  • 統計学とTwitterデータをからめる
  • Tweetによる各項目の予測値

などを予定しています。乞うご期待ください。それでは、よいPythonライフを!!

本記事に関連する過去の投稿は以下です。ご覧いただけると幸いです。

1件のコメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

ABOUT US

Baran-gizagiza
経歴:浪人→理系大学院卒業→大手製造業に就職(技術職)→アメリカ赴任中 仕事は、研究・設計など上流工程の仕事に携わっています。企業勤務を継続しながら、新しいことにチャレンジしたいと思い、ブログを下記はじめました。 このブログでは、趣味である 筋トレ(健康、ダイエット) AIとデータ(高校数学、プログラミング) 読書(主に自己啓発系) を中心に、人生経験やおすすめ情報の発信しています。