自然言語処理でツイートがバズるかを予測しようとした話

　
この記事は[ニフティグループ Advent Calendar 2019](https://qiita.com/advent-calendar/2019/nifty)の11日目の記事です。
昨日は@sonohaさんの「[Windows 10 HomeのWSL2でdocker-composeを使う](https://qiita.com/sonoha/items/33f1bc3b12f0803ceca7)」でした。
昔は環境差分で苦しむことが多かったですが、WSLやDockerでだいぶ便利になりましたね。

---

# はじめに
普段、[ニフティニュース](https://news.nifty.com/)というサイトの運用・開発の業務を行っています。その中で感じているのが、例えば[SmartNews](https://www.smartnews.com/ja/)・[Gunosy](https://gunosy.co.jp/)のような会社に代表されるように、情報を活用する=機械学習を活用するという時代になってきています。

特にニュースなどの文章情報を扱う際には、自然言語処理が必須になります。
そこで、自然言語処理を活用しつつ、面白いことができないかという試行錯誤のログを今回は残してみます。

# 自然言語処理とは
自然言語処理は簡単に言えば、人が話している言葉をコンピュータに認識させることの一連の技術を指します。

プログラミング言語はパターンに沿って設計されているので、コンピュータが解析するにも苦労しないのですが、人間が話している言葉はパターンが複雑だったり例外が多く、機械学習が活発に研究されている今でも難しい分野と言われています。

## 東ロボくん
自然言語処理が難しいことが端的に現れているのが、「東ロボくん」のプロジェクトです。

「東ロボくん」プロジェクトは、2021年までに東大に合格できるAIを開発するというプロジェクトですが、この中で一番難しい科目は国語のようです。プロジェクトが一段落した際に、全体の偏差値が57.1にも関わらず、国語だけは50を切る49.7ということで、コンピュータにとって読解というタスクが難しいことが分かるプロジェクトでした。

同様にリスニングについても芳しくなく、文脈をコンピュータで汲み取ることは難しいタスクであると考えられています。

## 近年の自然言語処理

近年では[BERT](https://github.com/google-research/bert)など深層学習系の自然言語処理モデルの出現で、読解系のタスクも克服に向かっているようです。
機械学習のブレイクスルーは止まる気配がなく、機械学習の活用という面で自然言語処理は今一番ホットな分野かもしれません。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">アリババの人工知能チームが <a href="https://twitter.com/Stanford?ref_src=twsrc%5Etfw">@Stanford</a> 大学の読解力テストで人間に始めて勝ったのが、今年の1月。スコアは、<br><br>・人：82.304<br>・AI：82.44<br><br>グーグルの《BERT》でトレーニングさせた人工知能のスコアは何と、87.433！10カ月で5ポイントも上げている。人間とマシン、読解力の差は今後更に広がる🤖。 <a href="https://t.co/by6NGJLNdT">https://t.co/by6NGJLNdT</a></p>&mdash; Sangmin @ChoimiraiSchool (@gijigae) <a href="https://twitter.com/gijigae/status/1058627711961198592?ref_src=twsrc%5Etfw">November 3, 2018</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">東大に合格できる賢いAIを作ろう！<br>→AIの読解力が低すぎて無理だった<br>→人間がAIに勝てるのは読解力だな！<br>→人間の読解力を調査しよう<br>→えっ、うそ？！人の読解力、低すぎっ！？<br>→ヤバイ、AIを教育してる場合じゃない！！！！<br>→実はAIも読解問題が得意でした<br><br>という流れ、もはやコメディだな</p>&mdash; 小猫遊りょう（たかにゃし・りょう） (@jaguring1) <a href="https://twitter.com/jaguring1/status/1196741706143522816?ref_src=twsrc%5Etfw">November 19, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おっ、「言語を理解するAI」を作るために必要となる複数の能力を評価するベンチマーク「GLUE」で、最高性能が8時間前に更新されていた。現在、マイクロソフトが作った「MT-DNN SMART」が一位。人間のスコアは現在9位！<a href="https://t.co/ht7qJwSWRu">https://t.co/ht7qJwSWRu</a> <a href="https://t.co/gsFfke19Sa">pic.twitter.com/gsFfke19Sa</a></p>&mdash; 小猫遊りょう（たかにゃし・りょう） (@jaguring1) <a href="https://twitter.com/jaguring1/status/1202747943821836289?ref_src=twsrc%5Etfw">December 6, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# ニュース記事を分類してみる
今回は自然言語処理の初歩として、単語の分散表現の学習とちょっとした応用をしてみます。
## fastText
[fastText](https://github.com/facebookresearch/fastText)は、Facebook Research AIが公開している自然言語処理ライブラリです。

自然言語処理のライブラリとして有名なものに[Word2Vec](https://opensource.googleblog.com/2013/08/learning-meaning-behind-words.html)というものがあります。これはGoogleが2013年に公開したライブラリであり、端的に言うと単語を数値に変換することが出来ます。fastTextはWord2Vecを発展させたライブラリです。
詳しくは：[FacebookのfastTextでFastに単語の分散表現を獲得する](https://qiita.com/icoxfog417/items/42a95b279c0b7ad26589)

これによって、それぞれの単語の「近さ」というものが定義できるようになり、例えば、「フランス」－「パリ」＋「東京」＝「日本」のような演算をすることができます。このような単語から数値への変換を、単語の分散表現と呼びます。

## Livedoorニュースコーパスを分類する
まず、[Livedoorニュースコーパス](https://www.rondhuit.com/download.html)のデータセットを分類するというタスクに挑戦してみます。

このデータセットはLivedoorニュースの記事データが入っており、ある記事がどのカテゴリ（9クラス）に分類されるかを予測するデータセットになっています。
やることは[Mecab](https://taku910.github.io/mecab/)で分かち書きを行い、fastTextで学習&予測という、自然言語処理でよくあるプロセスを踏みます。
多くの解説記事が出ていますので、やり方についてはここでは省略し、結果だけを示します。
手順：[Facebookが公開した10億語を数分で学習するfastTextで一体何ができるのか](https://deepage.net/bigdata/machine_learning/2016/08/28/fast_text_facebook.html#%E6%96%87%E6%9B%B8%E5%88%86%E9%A1%9E%E3%81%AB%E6%8C%91%E6%88%A6%E3%81%99%E3%82%8B)

手元で実際にやってみると、93%超えというかなりの精度で予測することが出来ました。

```
% ./fasttext supervised -input data/livedoor_train.txt -output result/livedoor -dim 10 -lr 0.1 -wordNgrams 2 -minCount 1 -bucket 10000000 -epoch 100 -thread 4
Read 4M words
Number of words:  97199
Number of labels: 9
Progress: 100.0% words/sec/thread: 2003045 lr:  0.000000 loss:  0.203106 ETA:   0h 0m
% ./fasttext test result/livedoor.bin data/livedoor_test.txt
N	727
P@1	0.935
R@1	0.935
```

fastTextにもニューラルネットワークの技術は取り入れられていますが、深層と呼べるような深いネットワークではないため、この分類はやや難しいタスクではないかと考えていました。しかし、実際には深層学習を使わないfastTextのような手法でも高精度で分類することが可能であり、実務で使う上では深層学習のような技術はオーバースペックな場面が多いのかもしれません。

# ツイートがバズるかを予測しよう
普段、自分はTwitterで情報収集をしつつ、面白いツイートが流れてくるのを楽しみにしているのですが、やはりバズるツイートというのは文章が秀逸な感じがします。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">【エンジニア用語解説】<br><br>「完全に理解した」<br>製品を利用をするためのチュートリアルを完了できたという意味。<br><br>「なにもわからない」<br>製品が本質的に抱える問題に直面するほど熟知が進んだという意味。<br><br>「チョットデキル」<br>同じ製品を自分でも１から作れるという意味。または開発者本人。</p>&mdash; 伊藤 祐策(パソコンの大先生) (@ito_yusaku) <a href="https://twitter.com/ito_yusaku/status/1042604780718157824?ref_src=twsrc%5Etfw">September 20, 2018</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

そこで、ある文章がバズるかを機械学習で事前に予測できないか、ということを自然言語処理を活用してやってみます。

あるツイートを入力として、出力をバズるorバズらないの二値問題として扱います。

## Twitterからツイートを集める
機械学習ではデータを集めることそのものが重要なプロセスです。データの量と質が高まるほど、良いモデルが作れると言われています。ここでは、Twitter APIを使って、ツイートのデータを収集してみます。

### Developerアカウントの申請
Developer用のアカウントを申請します。普段使っているアカウントでも問題ありません。
[解説記事](https://masatoshihanai.com/php-twitter-bot-01/)を参考に申請します。

途中で利用目的などがありますが、「自然言語処理を活用した機械学習モデルを学習させるため」というような文章を英語で入力すればOKです。

何日か申請に時間がかかるとのことですが、自分の場合はなぜか申請してすぐに開発者アカウントが使えるようになりました。

### APIを使ってツイートを収集する
Twitter APIが使えるようになったら、APIを使ってツイートを収集しましょう。
ここで、Favstarのようないいね数の多いツイートを収集しているサービスを活用しようと考えていたのですが、Favstar（とその類似サービス）はTwitterの仕様変更とともに終了していました……。

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Favstar is now offline.<br><br>Details: <a href="https://t.co/vZrDw2X4B7">https://t.co/vZrDw2X4B7</a><br><br>Good night. 😴</p>&mdash; Favstar.fm (@Favstar) <a href="https://twitter.com/Favstar/status/1010003517421993984?ref_src=twsrc%5Etfw">June 22, 2018</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

そこで、ここでは[日本Twitterフォロワーランキング](https://meyou.jp/ranking/follower_allcat)の上位200位のアカウントのツイートは基本的にバズっているとみなし、それらをポジティブデータとして入力することにしてみます。（これだとバズるかというよりは、フォロワー数が多くなるかという予測になっている気もしますが…）

ツイートを収集し、fastTextへ入力するための学習データを作ります。（[Github](https://github.com/reilow/tweet_predictor)）

APIを使うことで、あるアカウントのツイートのjsonを以下のようなコードで取得することができます。

```
params = {
            'screen_name' : screen_name,
            'count' : 200,
            'include_rts' : 'false'
            }
twitter = OAuth1Session(CK, CS, AT, AS)
req = twitter.get(API_URL, params = params)
```

収集できたツイートの一部を見てみます。
（\_\_label\_\_1がTOP200ツイート、\_\_label\_\_2はそれ以外）

```
__label__1,  ありがとう ござい ます ！ 
__label__1,  本日 は 、 武器 ガチャ に バレンタイン 武器 が 登場 する にゃ ٩(๑❛ᴗ❛๑)۶ 武器 スキル で キャラ が お菓子 を つくる ので 、 当たっ た 方 は お 試し ください (´ω｀*) # 白猫 
__label__2,  「 笑点 」 の 演芸 コーナー に 斎藤さん ＆ 窪田 さん が 出演 ！ 観客 を 前 に 大 緊張 の 2人 が マジック！ ！ 果たして ！ ？ そして ！ 2 shot 写真 は 、 スタッフ が 下手 な ので 斎藤さん が 自撮り 。 もっと 自撮り 見 た い人 は し て ね ♪ ＃ 斎藤工 の 自撮り ＃ 火村英生 
__label__2,  ここ から 右 に 入る と 美浦トレーニングセンター っていう 競馬 の アレ が あり まし て 、 そこ が 藤田菜七子 ちゃん の アレ な ん です よ ！ 菜七子 ちゃん かわいい 😍 
__label__1,  高熱 で 動け ない 人 に おすすめ する 食物 な ん だろ 。 ウイダーinゼリー か な ？ 
__label__1,  FULL MOON LIVE REPO in Nagoya Vol.2 💥 💥 💥 インタビュー に ご 協力 頂き まし た 皆さん ありがとう ござい まし た ✨ 🙏 ✨ ▼ HIROOMI TOSAKA from JSBIII Official Ch … 
__label__1,  【 重要 】 アルバム 収録曲 特典 大 公開 し て 雑談 する ╹ ω ╹ 
__label__2,  気 を つけ て 
__label__2,  ありがとう すき 🙏 
__label__2,  ご覧 いただき 、 ありがとう ござい ます 。 
```

うまく収集できました。が、人間にはクラスの差がよく分かりません…。

## ツイートの学習とテスト

収集したツイートデータをfastTextで学習し、分類してみます。

```
% ./fasttext supervised -input tweet_data/tweet_data_train.txt -output result/alpha_tweet -dim 10 -lr 0.1 -wordNgrams 2 -minCount 1 -bucket 10000000 -epoch 100 -thread 4
Read 15M words
Number of words:  245869
Number of labels: 2
Progress: 100.0% words/sec/thread: 2347018 lr:  0.000000 loss:  0.080234 ETA:   0h 0m
% ./fasttext test result/alpha_tweet.bin tweet_data/tweet_data_test.txt
N	59098
P@1	0.83
R@1	0.83
```

人間には違いが分からなかったクラス分けでしたが、テストデータに対して83%という精度でそれなりに分類ができています。

## 実データで予測してみる
実際にバズったツイートを入力して、精度を確認してみます。
バズツイートをラベル1、それ以外（バズツイートではない）をラベル2と予測し、表示されている数値はモデルがどれぐらいの確度で予測しているかを表しています。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">唐揚げはどこも美味しいから<br>点数は信じない。点数は全部100。</p>&mdash; 有吉弘行 (@ariyoshihiroiki) <a href="https://twitter.com/ariyoshihiroiki/status/1203689324824285184?ref_src=twsrc%5Etfw">December 8, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

```
1,:0.999954342842102,2,:6.569320248672739e-05,唐揚げはどこも美味しいから点数は信じない。点数は全部100。
```
フォロワー数日本一のツイートをバズるツイート（ラベル1）として、正しく予測できています。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ちょっと気が早いけど「ランドセル何色がいい？茶色？」とさりげなく私の好みをすり込もうとしたら、「ううん、赤とピンクと黄色で、真ん中に虹があって、泥棒が来たら音がなるボタンを押すと、カバンが金色に光るの」と言われたのですがイオンに売ってますか。</p>&mdash; さちうす子 (@kisekimachi) <a href="https://twitter.com/kisekimachi/status/1202893735056379905?ref_src=twsrc%5Etfw">December 6, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

```
2,:0.540506899356842,1,:0.4595131278038025,ちょっと気が早いけど「ランドセル何色がいい？茶色？」とさりげなく私の好みをすり込もうとしたら、「ううん、赤とピンクと黄色で、真ん中に虹があって、泥棒が来たら音がなるボタンを押すと、カバンが金色に光るの」と言われたのですがイオンに売ってますか。
```
確度的に50:50ぐらいだろうということで迷って、間違えています。
おそらく学習データがフォロワー数が多い人のツイートを取得しているだけなので、芸人のような短文ですっきりまとめるプロのツイートが多くなるためだと思われます。
（学習データ不足で、長文でのバズツイートは予測が難しい）

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">今月のJJに載ってた「モテる女のさしすせそ」、「そうなんだー！」を「ソクラテスみたい」に変えたの誰だよwwwwwww <a href="https://t.co/H23LipBX8z">pic.twitter.com/H23LipBX8z</a></p>&mdash; 最所 あさみ（asami saisho） (@qzqrnl) <a href="https://twitter.com/qzqrnl/status/1202046377309560832?ref_src=twsrc%5Etfw">December 4, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

```
1,:0.971310555934906,2,:0.02870946191251278,今月のJJに載ってた「モテる女のさしすせそ」、「そうなんだー！」を「ソクラテスみたい」に変えたの誰だよwwwwwww
```

これは画像も含んで1つのツイートとして成り立っているので難しいかと思われたのですが、高い確度でバズツイートと判定しています。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">笑いすぎて死ぬ人の心電図「wwwwwwwwwwwwwwwwwwww━━━w━━━w━━━w━━━━w━━━━w━━━━w━━━━━━━━━━━━━━━━━━」</p>&mdash; スマホなくした人 (@withoutXperia) <a href="https://twitter.com/withoutXperia/status/1202797301384671232?ref_src=twsrc%5Etfw">December 6, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

```
2,:1.0000098943710327,1,:1.0126519555342384e-05,笑いすぎて死ぬ人の心電図「wwwwwwwwwwwwwwwwwwww━━━w━━━w━━━w━━━━w━━━━w━━━━w━━━━━━━━━━━━━━━━━━」
```
こういうネタツイートは難しいですね。。。

# 終わりに
今回はTwitter+fastTextを使った自然言語処理に挑戦してみました。
やはり機械学習において重要なものはアルゴリズムよりも学習させるデータであると感じました。

今回はフォロワー数TOP200のデータを使ってみましたが、芸能人やYouTuberといった方々のツイートが多くなった関係で、データにも偏りがありました。
そのため、長文に弱かったり、「動画を上げました」というツイートをバズると判定してしまったりと、まだまだ甘い学習モデルが完成してしまいました。

機会があれば、いいね数の多いツイートをきちんと収集し、良質なツイートデータからモデルを構築してみたいと思います。

---

明日は@hmmrjnの「Webサイトもダークモード対応できるようになりました」です。お楽しみに。