はてなの金次郎

Pythonエンジニアの技術系ブログ

PyCon JP 2018でLTをしてきました 〜テキストマイニングによるTwitter個人アカウントの性格推定〜

はじめに

pycon.jp

PyConJP 2018で「テキストマイニングによるTwitter個人アカウントの性格推定」というタイトルでLTをさせていただきました。

普段はサーバーサイドエンジニアとしてスマホアプリのバックエンドサーバー開発を主にPython/Djangoで行っています。

LT参加の動機は、Pythonを使っている身として機械学習に触れてみたかったからです。

Webアプリケーション開発でしかPythonを使ったことがありませんでしたが、Pythonといえばデータサイエンスのイメージがあります。

採択されてもされなくても、PyConJPのLTという機会で普段は知らないPythonの一面を掘り下げてみようと思いました。

スライド

speakerdeck.com

YouTube

Gihyo

PyConJPの公式カンファレンスレポートで紹介していただきました。

正直「ちょっとストーカーの話っぽいけど大丈夫なの?」とスタッフ同士顔を見合わせる場面もあったのですが,終わってみると真面目でユーモアもある発表だったと思います。

gihyo.jp

Twitterの反応

Twitterで嬉しい反応をたくさんいただきました!ありがとうございます!

togetter.com

Twitterアカウントの性格推定

ツイートの収集

まずはツイートの収集です。Twitter社が提供するTwitter APIを利用してツイートを取得します。

クライアントの実装として、すぐにパッと思い付くのは requests を用いた実装です。

github.com

HTTP for Humans とデカデカと主張しているように、直感的にHTTPの通信を実装できます。

これは urllib2 の使いにくさを酷くディスった表現ですが、Python3で urllib.request が標準ライブラリとして提供されている今、 こちらを使うのも一つの選択肢ではないかと思います。

urllib2 と比べ格段に使いやすくなっています。

21.6. urllib.request — URL を開くための拡張可能なライブラリ — Python 3.6.5 ドキュメント

例えば、AWS LambdaをPython3で使う場合は外部ライブラリをimportするためには少々手間がかかるため、 urllib.request を選択するのが良いと思います。

今回のLTでは簡潔に実装できて、GitHubスター数もそこそこあったので python-twitter というライブラリを用いることにしました。

github.com

import twitter

api = twitter.Api(
    consumer_key=CONSUMER_KEY,
    consumer_secret=CONSUMER_SECRET,
    access_token_key=ACCESS_TOKEN_KEY,
    access_token_secret=ACCESS_TOKEN_SECRET
)

tweets = api.GetUserTimeline(screen_name='jumpyoshim', count=2)

collectionsのnamedtupleのようなデータ構造で返却されるため、注意が必要です。

IN

[tweet.text for tweet in tweets]

OUT

['RT @akucchan_world: 吉村さんのLTです。\n#pyconjp https://t.co/ZCvHY9ebcw',
 'PytestのTDD実践ためになった #pyconjp']

文章のベクトル化

続いて、収集したツイートを数値計算しやすいようにベクトル化します。

ベクトル化の手法として、3つほど確認できました。

tifana.ai

deepage.net

deepage.net

Word2VecやDoc2Vecに関しては、まだ咀嚼しきれない部分があったため、今回はBoWを選択しました。

BoWは、単語の頻出度のみを考慮して、単語の頻出度をベクトル化したものが最も近いデータを推定結果としているだけです。

Word2VecやDoc2Vecは単語の並び順なども考慮するらしく、推定精度が上がるらしいです。まだまだ勉強不足、今後の課題です。

形態素解析

ベクトル化するために、まずは形態素解析をする必要があります。

形態素解析のツールとして、3つほど確認できましたが、環境構築が容易で速度もはやいMeCabを選択してみました。

IN

import MeCab

tagger = MeCab.Tagger('mecabrc')
data = []
for tweet in tweets:
    node = tagger.parseToNode(tweet.text)
    words = []
    while node:
        meta = node.feature.split(',')
        if meta[0] == '名詞':
            words.append(node.surface.lower())
        node = node.next
    data.append(words)
print(data)

OUT

[['rt', '@', 'akucchan', '_', 'world', ':', '吉村', 'さん', 'lt', '#', 'pyconjp', 'https', '://', 't', '.', 'co', '/', 'zcvhy', '9', 'ebcw'], ['pytest', 'tdd', '実践', 'ため', '#', 'pyconjp']]

形態素解析の際、実際にはURLや@アカウント名、リツイートなどを正規表現で空文字で置換することで、形態素解析された際に意味をなさない単語を排除します。

MeCabJanomeに関してはpipでインストールできるため利用しやすいですね。

JUMANは環境構築がやや手間ですが、かなり高精度の形態素解析をしてくれるみたいです。

pypi.org

pypi.org

JUMAN - KUROHASHI-KAWAHARA LAB

特徴ベクトル

形態素解析した単語群は gensim を用いて辞書を作成し、ベクトル化します。

from gensim import corpora, matutils

dictionary = corpora.Dictionary(data)
data_train = []
for datum in data:
    bow = dictionary.doc2bow(datum)
    dense = list(matutils.corpus2dense([bow], num_terms=len(dictionary)).T[0])
    data_train.append(dense)
print(data_train)

OUT

[[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]]

github.com

文書分類器

ここまででデータを揃えることができたので、正解ラベルを用意して学習を行います。

正解ラベルはエゴグラムの診断結果を利用します。Twitter上にエゴグラムの診断結果をツイートするアカウントが多く存在するためです。

以下の23パターンがあります。

  • ネクラ厭世タイプ(W型)
  • 明朗楽観タイプ(M型)
  • 優柔不断タイプ(N型)
  • ハイパワータイプ(逆N型)
  • 頭でっかちタイプ(逆V型)
  • お手あげタイプ(V型)
  • 典型的ネクラタイプ(U型)
  • ぼんぼんタイプ(逆U型)
  • 頑固オヤジタイプ(左上がり型)
  • ガキ丸出しタイプ(右上がり型)
  • ハイレベルタイプ(オールA型)
  • 中庸タイプ(オールB型)
  • 原始人タイプ(オールC型)
  • ルーズタイプ(CP欠乏型)
  • クールタイプ(NP欠乏型)
  • 現実無視タイプ(A欠乏型)
  • 自閉症タイプ(FC欠乏型)
  • 気ままタイプ(AC欠乏型)
  • 口うるさタイプ(CP型)
  • お人好しタイプ(NP型)
  • コンピュータタイプ(A型)
  • 自由奔放タイプ(FC型)
  • 自己卑下タイプ(AC型)

機械学習

scikit-learn を利用することで簡単に機械学習ができます。

IN

from sklearn.ensemble import RandomForestClassifier

clf = RandomForestClassifier()
label_train = ['ネクラ厭世タイプ(W型)', '明朗楽観タイプ(M型)']
clf.fit(data_train, label_train)
clf.predict(data_train)

OUT

array(['ネクラ厭世タイプ(W型)', '明朗楽観タイプ(M型)'], dtype='<U12')

学習させたデータを推定してみると、当然同じタイプが推定されることが確認できます。

github.com

感想

たとえ数学的な知識に疎くても、gensimやscikit-learnといったライブラリを利用すれば簡単に実現できてしまうのがPythonのすごいところだと感じました。

今後は数学的な知識をより深めたり、機械学習をWebアプリケーションに組み込んだりしてみたいです。今後もPythonを使っていろいろなチャレンジをしていきたいです。

おわりに

今回はPyConJPということでPythongensimscilkit-learn などのライブラリを使って文書分類に挑戦してみましたが、Pythonにとらわれなければ他の選択肢が考えられました。

Facebookが開発しているOSSのfastTextや、GoogleのサービスであるGoogle Natural Language APIAWSのサービスであるAmazon Comprehendなどを利用するともっと簡単にテキスト分析ができるかもしれません。

fasttext.cc

cloud.google.com

aws.amazon.com

参考文献

以下の記事を大変参考にさせていただきました。深く感謝いたします。

qiita.com

qiita.com