Watsonに将来のキャリアを示してもらおう

最近猫も杓子もAIということで、システムエンジニアたるものお客様にあえば「これからは経営判断にAIを活用する時代ですよ」などと大上段に語っていると思います。そんなシステムエンジニアですから、自分自身の将来のキャリアについては当然AIに決めてもらうことが常識になってきました。

ということで、2015年のクリスマスは、Watson Natural Language Classifier (NLC)が将来のキャリアについてとても役に立つアドバイスをしてもらいましょう。

## 概要

エンジニアとしての今後を決めるにあたり、キャリア形成は非常に重要です。そして、自分の将来のキャリアを考えるには、自分とよく似た思考をもち、かつ成功している方のキャリアは非常に参考になると考えられます。自分とよく似た思考の人を数値化するということは以前は非常に困難なことでした。

しかし、今はtwitterがあります。Twitterでの発信が似ている人は思考が似ているという仮定をおきましょう。この仮定にもとづき、たとえば自社の退職者の退職前のツイートのうち、自分と似ている人を知ることが自分の将来のキャリアにとってとても参考になるでしょう。また、まだ退職していない人たちでも、自分と似ている人を知ることは有意義です。

そこで、具体的には以下の手順でキャリアの参考になる人を導出します。

* 対象となる会社を退職したエンジニア5名の退職前3ヶ月のtweetを吸い出す
* 対象となる会社で退職していないエンジニア5名の最近3ヶ月(2015/9/1〜2015/11/30)のtweetを吸い出す
* 吸いだしたtweetを適度に整形し、Watson NLCで分類器を作成する
* Webアプリで指定した対象者の直近20件のtweetを検索し、各tweetを分類器にかけて、確信度が高いと認識された件数が多いエンジニアを回答する

図示すると以下のようになります。

![tchart-overview.png](https://qiita-image-store.s3.amazonaws.com/0/21963/7a8920ca-2cca-4491-5dd8-72c0737e6b6c.png)

## 分類器の作成

### トレーニング用データの吸い上げ

Twitterから分類器のトレーニング用データを生成するには2つの方法があります。

* Twitter APIを使う(自動)
* 手作業

今回は対象が10件、かつ退職者の退職日を調べながらでしたので、以下の手順で手作業による吸い上げを行いました。

1. Twitter本家で「from:screen_name since:YYYY-MM-DD until:YYYY-MM-DD」による期間指定検索を行い、最下部までスクロールして検索結果を全件表示
2. Chrome上のスクレイピングツール[Scraper](https://chrome.google.com/webstore/detail/scraper/mbigbapnjcgaffohmbkdlecaccepngjd?hl=ja)でtweet本文のみを取り出し、クリップボード経由でエディタにコピー
3. 1行目(「Text」のみの行)と最終行(空行)を削除
4. 「twitter_{screen_name}.txt」というファイル名で保存

なお、具体的には、以下のアカウントのデータを利用しました。基準としては某社内外で知名度があり、某社のエンジニアであることが公開または事実上公開されており、tweetも比較的多いアカウントです。

* 退職者：keisuke69, kuranuki, namikawa, papanda, yohhatsu
* 未退職者：kawasima, minoruntw, n_matsui, shiraco, syobochim

### データの加工

各検索結果を同じディレクトリに置き、以下のスクリプトで(かなり雑ですが)加工してCSVに仕立て上げます。「リツイートしました」や「RT」など頻繁に出現する語句は極力削除しておかなければ、分類器がそれらに引っ張られるようです。また、元データには件数に大きな差異があるため、最大100件に揃えています。

```bash:create-training-data
for f in *.txt
do
    n=`basename $f .txt | sed 's/^twitter_//'`
    cat $f |
    sed '/さんが追加$/d;
        /をリツイートしました$/d;
        s/https\?:[A-Za-z0-9./~_&#\-]*//g;
        s/@[A-Za-z0-9_]*//g;
        s/#[^ ]*//g;
        s/さんから$//g;
        s/RT//g;
        s/[［【].*[］】]//g;
        s/%[A-Fa-f0-9]*//g;
        s/[…「」",]//g;
        s/\xc2\x91\|\xc2\x92\|\xc2\xa0\|\xe2\x80\x8e//g; # unicode non-breaking space
        s/^[ 　\t]*//g;
        s/[ 　\t]*$//g;
        /^$/d' |
    head -100 |
    awk "{printf \$0 \",$n\\n\"}" >> training.csv
done
```

### 分類器の作成

Watson NLCで分類器を作成します。

```bash
# Bluemix上のWatson NLCサービスとクレデンシャル情報の作成
$ cf create-service natural_language_classifier standard tchart
$ cf create-service-key tchart credentials
$ cf service-key tchart credentials # {username}と{password}を書き留めます

# 分類器の作成
$ curl -s -u "{username}:{password}" -X POST -F training_data=@local/training.csv -F training_metadata="{\"language\":\"ja\",\"name\":\"tchart\"}" https://gateway.watsonplatform.net/natural-language-classifier/api/v1/classifiers

# トレーニングステータスが'available'になるまで待ちます
$ curl -s -u "{username}:{password}" https://gateway.watsonplatform.net/natural-language-classifier/api/v1/classifiers/{classifier_id}
```

### 分類器のテスト

それでは、分類器を使用してみましょう。

```shell-session
$ curl -s -u "{username}:{password}" -X POST -H "Content-Type:application/json" -d "{\"text\":\"システム エンジニア\"}" https://gateway.watsonplatform.net/natural-language-classifier/api/v1/classifiers/{classifier_id}/classify | jq '.classes[0]'
{
  "confidence": 0.9756936502949977,
  "class_name": "kawasima"
}
$ curl -s -u "{username}:{password}" -X POST -H "Content-Type:application/json" -d "{\"text\":\"パブリッククラウド\"}" https://gateway.watsonplatform.net/natural-language-classifier/api/v1/classifiers/{classifier_id}/classify | jq '.classes[0]'
{
  "confidence": 0.981873424923837,
  "class_name": "n_matsui"
}
```

## Webアプリ

今回使用したコードは以下のところにあります。

* https://github.com/blackaplysia/tchart.git

Webアプリは、以下の構成です。

* node.js+express
* twitter (npm): twitter APIからユーザタイムラインを取得するためのnpmモジュール
* watson-developer-cloud (npm): Watson NLCで分類を実行するためのnpmモジュール

TwitterとWatsonにアクセスするための情報は、それぞれ環境変数でもつようにしています。

| 変数 | 値 |
|:---|:---|
|TWITTER_KEY|Twitter API Key|
|TWITTER_SECRET|Twitter API Secret|
|TWITTER_TOKEN|Twitter Access Token|
|TWITTER_TOKEN_SECRET|Twitter Access Token Secret|
|WATSON_NLC_CREDENTIAL|NLCユーザ名:NLCパスワード|
|WATSON_NLC_CLASSIFIER|NLC分類器ID(classifier_id)|

分類器を呼び出すコードはroutes/chart.jsに記述されています。おおまかには以下のような動作をします。

* Twitterのユーザタイムラインを取得し、tweetsに格納
* tweetsからそれぞれのtweetを取り出してNLCで分類し、分類結果をchartsに格納
* すべての分類が終了した時点で、分類クラスごとに確信度0.8以上のものだけをサマリし、サマリ結果をtopsに格納
* topsの中でもっとも件数が多いもの、または件数は同じだが平均確信度が高いものを返す

## 実行結果

```shell-session
$ curl -s http://localhost:3000/chart/blackaplysia
<!DOCTYPE html><html><head><title>進路</title><link rel="stylesheet" href="/css/styles.css"></head><body><h1>あなたの参考になるキャリアは kuranuki です。 (確信度: 0.9609436602751452)</h1></body></html>
$ curl -s http://localhost:3000/chart/ike_dai
<!DOCTYPE html><html><head><title>進路</title><link rel="stylesheet" href="/css/styles.css"></head><body><h1>あなたの参考になるキャリアは namikawa です。 (確信度: 0.946550371660685)</h1></body></html>
$ curl -s http://localhost:3000/chart/tenten0213
<!DOCTYPE html><html><head><title>進路</title><link rel="stylesheet" href="/css/styles.css"></head><body><h1>あなたの参考になるキャリアは syobochim です。 (確信度: 0.9270430676457629)</h1></body></html>
```

## まとめ

クリスマスが過ぎると冬休みです。Watson NLCと一緒に将来のキャリアを考えてみてはいかがでしょうか(←適当)。