自分をコピーするbotを作る

自分のTwitterアカウントをコピーするbotを簡単に作れるmirror botというものを作りました。@naoty_botはこれを使って作りました。

@naoty_k なんでわざわざ大金払って太ろうとしてるの?バカなの?

— なおてぃー(bot) (@naoty_bot) 2014, 11月 10

コピーbotを作る手順

1. bot用のアカウントを作ります。

2. 人間とbotそれぞれのアカウントでTwitterアプリケーションを作ります。ここから作れます。そして、人間とbotの両方のアカウント用の「Consumer Key」「Consumer Secret」「Access Token」「Access Token Secret」を取得します(下のスクショのモザイクかかってるところです)。

f:id:naoty_k:20141110230321p:plain

f:id:naoty_k:20141110230752p:plain

f:id:naoty_k:20141110230803p:plain

追記 : bot用のアプリケーションを作成する際、権限を Read and Write にする必要があります。一度Read Onlyでアクセストークンを発行している場合は権限を変更した後もう一度発行しなおして、Herokuアプリケーションの環境変数を新しいアクセストークンに替えてください。

3. こちらのHerokuボタンを押します(別サイトに飛びます)。もしHerokuのアカウントがなければ作ってください。

Deploy

4. 適当なHerokuアプリ名を入れて、「Env」の各項目に2.で取得した「Consumer Key」「Consumer Secret」「Access Token」「Access Token Secret」を入力します。人間のアカウントのものは「HUMAN_*」に、botのアカウントのものは「BOT_*」に入れていきます。

f:id:naoty_k:20141110232038p:plain

5.「Deploy for Free」ボタンを押してしばらく待ちます。Herokuにアプリケーションがデプロイされます。その後、アプリのダッシュボード画面で以下のようにdynosを1xにすると、アプリケーションが起動します。

f:id:naoty_k:20141110232352g:plain

6.終わり。

コピーbotの機能

  • 過去のtweetからランダムに選んで投稿します。ランダムに選ぶとき、現在の時間帯を考慮します。だから、朝には朝っぽいことをtweetするはずです。
  • 一日のtweet数やどの時間帯にtweetされる傾向があるかを計算し、そのパターンに従います。例えば、一日にたくさんtweetする人のbotはたくさんtweetしますし、あなたが通勤時間と帰宅時間にtweetする傾向があると、botもその時間帯にtweetする確率が高いです。
  • 話しかけるとreplyを返します。replyは過去にあなたがその人に返したreplyからランダムに選ばれます。
  • あなたがfavりやすいtweetを学習し、favります。

技術的な話

tweetするタイミングの決定

人間のtweetはHeroku Postgresqlのfree planの上限である10000レコードまで保存されます(上限を超えると古い順に消します)。そのとき、一日の中で何分目に投稿されたかを同時に記録します。たとえば、01:00の投稿は60分目だし、02:00の投稿は120分目、23:59の投稿は1439分目となります。すると、投稿数が多い分と少ない分がわかります。なので、n分に投稿される確率=n分の投稿数/総投稿数を計算することができます。ここから0分から1359分までの確率分布を作ることができます。この確率分布を累積分布にすると実装が簡単になります。そして、0から1までの乱数を生成して累積分布上の重なる分数をbotがtweetする分数として決定します。これを一日にtweetする回数分行い、その日tweetする分を事前に決定しておきます。

以上のようなことを行っているのが./lib/mirror_bot/scheduler.rbというファイルです。

favりやすいtweetの学習と分類

人間は大量に流れてくるtweetの中から特定のtweetだけを選んでfavっています。この行動は大量のメールの中から迷惑メールだけをゴミ箱送りにする行動と似ています。つまり、大量のデータから特定のカテゴリーに含まれるものを識別する、という問題に一般化できると考えました。そこで、スパムフィルタリングと同じアルゴリズムで、大量のtweetから特定のtweetだけをfavoriteというカテゴリーに分類する実装をしました。

スパムフィルタリングの実装はごく普通のベイジアンフィルタです。簡単に言ってしまうと、favられたtweetに含まれやすい単語とか含まれにくい単語を調べていくということをしていきます。形態素解析にはokuraを使いました。とても便利でした。各単語の各カテゴリーに含まれた回数はRedis(redistogo)に保存しています。

以上のようなことを行っているのが./lib/mirror_bot/classifier.rbというファイルです。

事前学習とHerokuボタン

以上の2つのモジュール、schedulerとclassifierを機能させるには事前に多くのデータを学習させることが必要です。schedulerについては過去3,200件のtweet、classifierについては800件ずつのfavったtweetとfavってないtweetを学習させています。これを行っているのがtrainerです。trainerは./lib/mirror_bot/trainer.rbで定義されており、./bin/mirror_botスクリプトから実行します。

Herokuボタンからbotをデプロイする場合、デプロイして起動するまでにtrainerを実行する必要があります。Herokuボタンによるデプロイを設定するapp.jsonにはscriptsという項目があり、こうしたセットアップのための設定が可能です。以下のように指定するだけです。

{
    "scripts": {
        "postdeploy": "bundle exec sequel -m migrations $DATABASE_URL && bin/mirror_bot train scheduler && bin/mirror_bot train classifier"
    }
}

これでデプロイしてから起動する直前に事前学習を実行することができました。

なぜ作ったか

最近、機械学習とか自然言語処理に興味が出てきて勉強をしはじめたのですが、何か具体的な目標がほしいと思って「ちょっと賢いbot」を作ることにしました。いろいろ試行錯誤した結果、自分の行動パターンを学習してまねするbotを作ることにしました。

得られた知見

  • botっぽいアイコンはhttp://robohash.org/で生成できて便利。
  • botによる発言を自動生成させようと試行錯誤したけど、結局コピーにすることにしました。まず、マルコフ連鎖を使った文章生成はbotっぽいけど人間らしさはないので、今回は却下。次に、word2vecを使って文章に含まれる単語を類義語と入れ替えることで似たような文章の生成を試みました。word2vecをRubyから使う術がないので、別プロセスでPythonのgensimを使った類義語サーバーを立ててプロセス間通信でRubyに返すみたいな実装をしてみました。ですが、これだとそもそもHerokuの無料枠では不可能でした。さらに、word2vecで使われるモデルファイルが大きすぎてディスクにのっかりません。VPSで挑戦してみましたが、今度は1GBのメモリにのっかりきらずに動きませんでした。思ったほど意味の通じる文章を生成できるわけでもなかったので、この方法は諦めました。
  • herokuのオペレーションをスムーズに進めるときにhttps://github.com/ddollar/heroku-confighttps://github.com/ddollar/heroku-redis-cliが便利でした。

参考

集合知プログラミング

集合知プログラミング

はじめてのAIプログラミング―C言語で作る人工知能と人工無能

はじめてのAIプログラミング―C言語で作る人工知能と人工無能