EnsekiTT Blog

EnsekiTTが書くブログです。

形態素解析曰くツイッタラーの日本語は度し難く、決定木曰くエンジニアは「好き」って表明をあんまりしないらしい話

つまりなにしたの?

前回、「おっぱい」とつぶやいていたら本当にエンジニアなのか決定木に確かめてもらった話の準備をした。
一通りできたので実際にやってみたらエンジニアは「好き」をよく表明しているのかもしれない。みたいな知見が得られた。
もちろん適当実装だし乱数も使ってるし取得を開始する時刻によって結果はぜんぜん変わるんだけど、
ジニ係数の高いところによく「好き」って単語を使っているかってところが現れた。
ensekitt.hatenablog.com
f:id:ensekitt:20171008120350j:plain
*1

今回の目的変数

このツイッタラーはエンジニアかどうか。

データセット

僕がフォローしてる方から鍵ではないアクティブなツイッタラーを選ぶ。
アクティブの定義は5000ツイート以上していて、半年以内に1000ツイート以上してる方とする。
アクティブなツイッタラーからエンジニアと非エンジニアをnアカウント*2ずつ選ぶ。
(せめてn=50のつもり)
真にエンジニアかは知らない人もいるけど、プロフィールやツイートから僕が判断する。*3
100アカウントのリプライ以外のツイートを過去500ツイートを抽出する。
いらん文字とか、表記ゆれが起きがちな表現を多少マシにする
構文解析器にかけて名詞を抽出し、ベクトルにする。
ここで、ベクトルは、Wordに対応する結構次元数の多いスパースなベクトルになって、
発言していたらそのWordに対応するところが1インクリメントされる。ってことにしてみた。
これをデータセットとする。
(自然言語処理とかに明るくないのでこの辺正しいのか怪しいです。コメントいただけるとうれしいです。)

評価

今回の評価は識別能力の良し悪しではなく、何がこの2つの集団を分かつのかを知ること。
今回のやり方だと識別能力は多分低い。

どんな感じでやったのか

1. まずTwitterの機能(リスト)を使って、エンジニアと非エンジニアのリストを作成した。

 (これがだいたい3時間位かかった。なにせ僕がフォローさせていただいている皆さんエンジニア比率が高くて
  非エンジニアかつ鍵じゃない人ってあんまりいなくて大変だった。ちからつきて50vs50ってことにした。)

2. TwitterAPIを叩いて、リストメンバーとそのリストメンバーのツイートを取得した。

 (15分間に1500回くらい叩けるけど、念のため1秒に1回位取得することにした。
  一部、リツイートとリプライが多くてうまく取得できない人もいたのでユーザを切り替えた。)

3. JanomeMeCab)の形態素解析に1ツイートずつ突っ込んで中身を見た。

 (ツイッタラーの度し難い日本語を目の当たりにする。なんて日本語使いやがるんだと思って自分のツイートも突っ込んでみたけど、安定の度し難さだった。)

3.1 まずアルファベットと数字はめんどくさいので削除
3.2 記号が一部サ変扱いになるようで顔文字に使われる記号をちまちま追加した(辞書を追加するか迷ったけど、そのへんのやり方わからないから目についたやつだけ削除した)
3.3 助詞や助動詞、接頭詞とかを削除
3.4 動詞と形容詞は活用前に戻すことにした→その後動詞はやめた。
3.5 連続している名詞は複合名詞にした(ツリー表示した時面白い単語が出てくるため

 

4. 疎ベクトル化してみる

 ここが一番不安。下図のようなとても次元数の多い疎ベクトルをユーザごとに作ってみた。
 昔ゼミで言語系をやってた人が似たようなことを言っていたような…といううろ覚えな感じでこの方式を選択した。
 f:id:ensekitt:20171008111346p:plain
 普段全く自然言語を扱わないので3,4は不安要素が多いしめんどくさいからいいかーと妥協した要素が多い、
 「みんなそんな苦労してないよ」って部分と「ここはまだ人が頑張らなきゃいけないんだよ」って部分の勉強が全然追いついていないから
 無駄があるかもしれないし必要な前処理が足りていないかもしれない…
 

5. 決定木のインスタンスを作成して学習する

 Scikit-learnの決定木を使って、さっきの疎ベクトルを学習させて、とりあえず学習データの分類結果を確認してみた。
 前回の記事の通り、ジニ多様性指標を使って木の深さはとりあえず6にした。(面白いから幾つか試行錯誤して遊んだ)
 その学習結果の木がこちら。
f:id:ensekitt:20171008112058j:plain
感電上等ってなんですかね(困惑
左に行くとTrueで右に行くとFalseです。箱の中の一番下にどちらのクラスについて判別したかが書いてあり、一番上にその単語の出現閾値が書いてあります。
たとえば1番上の「好き」だと「好きが2.5回以下だと左下。2.5より大きいと右下。」その先を見ていくと殆どのエンジニアが左下側の枝にくっついてる。
これはエンジニアがもっと好きなことを好きって言うべきなんじゃないか?
ただ、ぼくがフォローしてる界隈「すこ」とか言い出すので本当に度し難い。

6. 一応10-fold 交叉検定して過学習なことがわかったので、対策する

さっきのパラメータで交叉検定をすると
スコアは0.61
最大でも0.9とか最小だと0.4…
(1になるほどよいよ)

どう考えても次元数に対してデータセットが少ないけど悪あがきする。
というわけで以下2つの対策をうってみた

  • 子ノードのデータ数の最小値を設定→子ノードに2ユーザ以上含まれるような制限
  • ツリーの深さを制限する→さっきは6だったけど半分の3にした

これでやってみると、
f:id:ensekitt:20171008113911p:plain
スコアは微増の0.63
ただちょびっと安定したのか最大が0.8、最小が0.5(ランダムかな…?)
「好き」って分類は変わらなかった。
ちなみに、決定木の生成は乱数も利用してるので実行するたびに結果が変わる。
見てる分とかCrossValidationしてる時は良いけど、ちゃんと実験する時は固定値になるようにした方がいい。

7. 一応おっぱいプレディクションを試す。

今回のデータセットだと0.56。若干エンジニアのほうがおっぱいとつぶやいているみたいだけど大した差はなさそう。
100人中42人がおっぱいってつぶやいているタイムラインに僕がいることだけはわかった。
僕のタイムラインはエンジニアかどうかよりもおっぱいを尊いと感じている人のほうが多いんですね。安心しました(?


コード(元はJupyter Notebookでやっていたので見にくい)


http://ensekitt.hatenablog.com/entry/2017/10/06/23 ...

まとめ

どうあがいてもデータセットを作るのが大変すぎて大変。

謝辞

皆さんのツイートを利用させていただきありがとうございました。

*1:unsplash.com

*2:作成中

*3:これが可視化されてる可能性もある