Twitterに投稿された新型コロナウィルスに関するツイートを分析してみた

# 概要
Twitterでは，新型コロナウィルスに関して日夜活発に議論されています．
これらのツイートを分析することで，Twitterユーザの傾向として意義あるものが掴めないかと思ました．
そこで，本記事では，Twitterに投稿された新型コロナウィルスに関するツイートを収集し，簡単に分析をしていきます．

誤りや見づらい箇所，アドバイス等ございましたら，どうぞご気軽にご指摘ください．よろしくお願いします．

# データの詳細
本記事で用いるツイートデータは，2020年1月1日～2020年4月1日までの間に投稿された，「コロナ」「COVID-19」「感染症」のいずれかを含むツイートです．
ただし，日本語ツイートに限定し，RT数が100を越えているツイートのみを用います．
結果として，47041件のツイートからなるデータセットを構築しました．

ツイートデータは以下のような連想配列で保存しました．

```
{
'text': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 
'date': datetime.datetime(2020, 1, 1, 1, 0, 1),
'retweets': 123,
'favorites': 456,
'user_id': 7890123,
'hashtags': ['# yyy', '# zzz'],
'url': ['https://aaaaaa.com', 'http://bbb.com']
}
```

# 探索的データ分析 (Explanatory Data Analysis: EDA)
本記事で用いるデータからは，テキストの長さ，投稿時間，RT数，いいね数，ハッシュタグの有無，URLの有無といった，いくつかの量が得られます．
そこで，これらの量を活かしてデータの特性を読み取ります．

※以下すべてpython3 + Jupyter Notebookを用いて処理しています．

```python
import os, sys, json, re
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()
from datetime import datetime
import datetime as dt
%matplotlib inline
```

### 文字数，RT数，いいね数，URLの有無，ハッシュタグの有無
##### 文字数

```python
tweet_len = tweets["text"].str.len()
tweets["text_len"] = tweet_len
tweets["text_len"].hist(bins=range(0, 141, 5))
plt.xlabel("len. of text")
plt.ylabel("num. of tweets")
plt.title("Histgram on length of texts in tweets")
```

![文字数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612953/1860bc7d-b3ba-6a0f-e120-be4ee649f581.png)
データ取得の時点では，140字を越えるツイートが少数見られましたが(なんで？)，図の見やすさのために省きました．
データセット内の多くのツイートが，多くの文字(≒情報)を含むようです．
本データセットには10RTを越えるツイートのみを採用しているので，もしかしたら文字数が増加するほどRT数が増加する傾向にあるのかも知れません．(この点は下で検証しています．)


##### RT数，いいね数
```python
tweets["retweets"].hist(bins=range(0,4001,100))
plt.xlabel("num. of RT")
plt.ylabel("num. of tweets")
plt.title("Histgram on the number of RT.")
-------------------------------------------------
tweets["favorites"].hist(bins=range(0,4001,100))
plt.xlabel("num. of favorites")
plt.ylabel("num. of tweets")
plt.title("Histgram on the number of favorites.")
```

![RT数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612953/632fdca5-1aac-69cc-13af-bf5fc24e2f55.png)![いいね数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612953/b211aedd-96bc-dcf3-72fd-70231bf4e02d.png)
実際には10万RT/いいねを越えるツイートもあるのですが，図の見やすさのためにこのように範囲を設定しています．
両者とも減衰がみられますが，RT数で～300程度まではツイート数が上昇傾向にあることから，いったんRTされはじめたツイートはある一定のラインまではRT数が伸び続ける傾向にあるのでは無いかと推測できます．


ここで，RT数と文字数の相関関係を見てみます．

```python
fig, ax = plt.subplots()
ax.scatter(tweets["text_len"], tweets["retweets"], s=1)
plt.xlim(0, 140)
plt.ylim(0, 5000)
plt.xlabel("len. of texts in tweets")
plt.ylabel("num. of RT")
plt.title("Scatter plot of RT and len. of texts.")
```
![文字数とRT数の相関.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612953/572256f9-fefd-fb58-8879-63dbc7fe9fa6.png)
相関係数: 0.022
図を見ると文字数が140に近い所ではRT数も大きいツイートが多いように見えるのですが，相関関係は無いようです．
したがって，「たくさんRTされるツイートは，文字数が多い傾向にある」といったことやその逆は言えないようです．

##### ハッシュタグ/URLの有無
```python
tweets.loc[tweets["hashtags"].str.len() > 0, "has_hashtag"] = 1
tweets.loc[tweets["hashtags"].str.len() <= 0, "has_hashtag"] = 0
tweets["has_hashtag"].hist()
plt.xlabel("has hashtag (1) or not (0)")
plt.ylabel("num. of tweets")
plt.title("Histgram of whether tweets have hashtag(s) or not.")
----------------------------------------------------------------
tweets.loc[tweets["url"].str.len() > 0, "has_url"] = 1
tweets.loc[tweets["url"].str.len() <= 0, "has_url"] = 0
tweets["has_url"].hist()
plt.xlabel("has URL (1) or not (0)")
plt.ylabel("num. of tweets")
plt.title("Histgram of whether tweets have URL(s) or not.")
```

![ハッシュタグの有無.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612953/ed932e69-ea97-9cf5-492b-3755f7eae46e.png)![URLの有無.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612953/e5782d85-9f93-631f-f786-7ad7ccf12018.png)
このデータセットでは，ハッシュタグが付与されたツイートは少なく，URLが付与されたツイートが多いようです．
半数以上のツイートにURLが付与されていることから，RT数が10以上のツイートの多くは本文だけで無く，URLによっても情報を付与していることがわかります．


##### ここまでのまとめ
このあたりは一般のツイートと同様な特性が見られるようです．
(実際には一般のツイートでデータセットを作り，同様の量をだして比較する必要がありますが･･･)
データセットのツイートには，本文が長く，ハッシュタグよりもURLによって情報を付加する傾向にあります．
RT数，いいね数に関してもキレイに減衰する傾向がみられ，これは一般のツイートでも同様であると考えられます．

### 時系列を用いた分析
以降では，1/1から4/1までの92日間での種々の量の変遷をみていきます．


##### 日ごとのツイート数

```python
sns.set()
fig, ax = plt.subplots(figsize=(16.0, 8.0))
ax.bar(df.index, df["tweets"], color='#348ABD')
ax.plot(df.index, df["kansen"], color="blue")
ax.set_xticks([1,32,61,92])
ax.set_xticklabels(["01/01", "02/01", "03/01", "04/01"])
ax.set_xlabel("date")
```
![日ごとのツイート数2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612953/4cc3eb66-ede3-0fe6-c602-0a7b037511a9.png)

横軸は日付です．
ヒストグラムが日ごとのツイート数を表し，折れ線が日ごとの国内での新型コロナウィルス感染判明数[^1]を表します．
縦軸の目盛りは両者に共通です．

上図ではいくつかのピークが確認できます．
各ピークに関して，1日だけ飛び抜けるわけではなく，2，3日に渡ってツイート数が増加しています．
このことから，こうしたピークは外れ値ではなく，この期間にはユーザの関心を強く引く事柄が存在したと予想されます．

また，感染判明数もついでに載せましたが，ツイート数とはそれほど相関がないようです．~~苦労したのに~~
このことから，ユーザは新型コロナウィルスの患者数増加(感染拡大)よりも，その結果もたらされる他の事象(例えば政治的判断やイベントの中止など)に強く反応すると予想されます．

では，各ピークは何が原因で生じているか分析します．

![日ごとのツイート数_mod.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612953/bfa22262-c639-1f5a-7c8c-f49f809858ef.png)


この図は，先ほどの図のピークや個人的に気になる日に関して，実際のツイートの内容や厚労省の発表等を調査し，ピーク等の事象の原因になったと思われる内容を付与したものです．

肝心の1/28付近と2/26付近に関して，いずれもデータセット内の100件以上のツイートに目を通しましたが，一貫性が無く，何がピークの原因となっているかは確認できませんでした．
こちらは，後ほど頻出語やRT数に関する分析を行う際に，詳細に確認します．多分

##### 日ごとの累計RT数

```python
sns.set_style("dark")
fig, ax1 = plt.subplots(figsize=(16.0, 8.0))
ax1.bar(df.index, df["retweets"], color='#348ABD')
ax2 = ax1.twinx()
ax2.plot(df.index, df["kansen"], color="blue")
ax2.set_ylim(0,2500)
ax1.set_xticks([1,32,61,92])
ax1.set_xticklabels(["01/01", "02/01", "03/01", "04/01"])
ax1.set_xlabel("date")
ax1.set_ylabel("num. of retweets")
ax2.set_ylabel("num. of infected people")
```
![日ごとの累計RT数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612953/15e1f9b7-45d8-cf79-325f-5bc73f193dd1.png)
上図で，ヒストグラムと左縦軸は日ごとの累計RT数を表し，折れ線と右縦軸が日ごとの感染判明数を表します．
日ごとのツイート数と同じようなグラフが出てきました．
やはり，日ごとの感染判明数とは関連が無さそうです．

では，日ごとのツイート数と日ごとのRT数を比較してみます．

```python
sns.set_style("dark")
fig, ax1 = plt.subplots(figsize=(16.0, 8.0))
ax1.bar(df.index, df["tweets"], color='#348ABD', alpha=0.7)
ax2 = ax1.twinx()
ax2.plot(df.index, df["retweets"], color="red")
ax2.set_ylim(0,3000000)
ax1.set_xticks([1,32,61,92])
ax1.set_xticklabels(["01/01", "02/01", "03/01", "04/01"])
ax1.set_xlabel("date")
ax1.set_ylabel("num. of tweets")
ax2.set_ylabel("num. of retweets")
```

![日ごとのツイート数_日ごとのRT数_mod.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612953/afd9538b-48c2-0151-d774-f3d2461e14ff.png)
上の図で，ヒストグラムと左縦軸が日ごとのツイート数を表し，赤の折れ線と右縦軸が日ごとの累計RT数を表します．
日ごとのツイート数と日ごとのRT数は，ほとんどの日で相関関係にあるようです．
ここで，3/25~28付近だけ，他とは異なる様相を呈しています．
他の人比較して(10RT以上された)ツイート数がRT数を上回る原因として，この期間だけ，他の期間と比較して新型コロナウィルスに関する話題が多く，ユーザが話題を追い切れなかった(RTできなかった)ことが考えられます．


# 今後
~~さっさと投稿したかったので~~上記を踏まえ，今後やることを書いていきます．

- 頻出語の分析
    - 1/24，2/26あたりになぜピークがあるのか．
    - WindowsのMeCabがなぜかうまくいかない．
- ツイートのクラスタリング
    - 例えば日ごとにツイートをクラスタリングすることで，その日の話題の数が定量化でき，ツイートの内容もまとまってより分析しやすくなると期待できます．
- RT数予測モデルの構築
    - 適当な回帰モデルを組んで，「どういう性質のツイートがRTされやすい(≒人の興味を引く)か」といったことを分析できるかも...?
    - 問題を分類にしても良さそう．
- ユーザ情報の活用
    - 例えば専門家のツイートは，そうでないユーザよりRT数が多くなるでしょう．このように，投稿者の情報を活用することで，より詳細に新型コロナウィルスに関するTwitterユーザの動向が分析できる可能性があります．

# おわりに
はじめてQiitaに投稿します．
分析として，なにか革新的な知見が得られた訳ではありませんでしたが，今後このデータセットについて掘り進める方針が掴めた気がします．
EDAは，こうした方向性を決めるためにも重要なのですね．
本当はしっかり予測モデルまで構築して，評価・モデルの性質の分析までしたかったのですが，はよ投稿したいという気持ちが強く，次回に回すことにしました．

ここまで読んで頂き，ありがとうございました．
拙い分析・文章で恐縮ですが，ご指摘・ご意見，アドバイス等お気軽にして頂ければと思います．

[^1]: 参考: https://www.asahi.com/special/corona/