Atsumaru Engineer's Blog

集客プラットフォーム事業を手がける株式会社あつまるのエンジニアブログです

【機械学習】中国人新卒エンジニアが機械学習と格闘した話。

f:id:snoopy_no_sora:20181211101938p:plain:w200

こんにちは。
渡邊です。

さっそく余談を。
ちょっと前に、Twitterで「Twitterのユーザー名に、今の天気と連動した天気アイコンを入れる」というのが流行りました。
あれ、実装してみると、ちょっと感動ですよ。
「あ、たしかにこうやるとできるな。」って。
しかも、朝Twitterチェックすればその日の天気もわかるという(⇦これは本当に便利)。
そこまで難しい技術ではないので、まだやったことない人にはおすすめです。

↓↓山本一成さんのQiita記事
Twitterの名前を5分毎に東京の天気⛅☂☃と連動させるサーバレスプログラムを書いたら色々知らないことが出てきた話

さて、本題

話を戻しますと、弊社の新卒が機械学習を触ってみた話です。

10月、弊社に中国から2人の新卒エンジニアが入社しました。
弊社はデータ分析をやっているので、機械学習は必須なのですが、2人ともやったことがないとのこと。

それはやってみなきゃ!!

しかし、いきなり「データがどーのこーの」「モデルがどーのこーの」という小難しい話をしても、おそらく2人ともぽかーんです。
さて、どうしたものか…。

やはり、2人が興味ある分野で実際に手を動かしてみるのが一番良いだろう。
そこで気づいたのが、2人とも

アイドルが大好き

だということ。

1人はTW○CEの、もう1人は乃木○46のファン。
(乃木○46ファンにいたっては、土日に上海まで遠征するガチっぷり)

そこで、アイドルの身長などのデータを作って、それぞれのグループの傾向を出して予測するモデルを作ったら面白いんじゃないかなと。

やってみました。

※今回は新卒に機械学習の雰囲気を掴んでもらうために作ったので、細かいツッコミはなしでお願いします()

ゴール

「髪の長さ」「身長」「目」「髪の色」を入力し、どのグループに属するかを予測するモデルを構築する。 f:id:snoopy_no_sora:20181210231917p:plain

環境

【エディター】 Visual Studio Code(拡張機能でJupyter Notebookを入れています)

【言語】 Python 3.6.5

実装①データセット作成

まずは、データの準備です。
今回は、「韓国アイドル」「乃○坂46」「ハリウッド女優」の3種類でデータセットを作りました。 (「ハリウッド女優」の理由は、他2つと明確に異なる特徴量がありそうだなと思ったため)

それぞれのアイドル・女優の、特徴量を定めます。

# データセット
# 髪の長さ(cm)、身長(cm)、目(二重:0, 一重:1)、髪の明るさ(明るい:0, 暗い:1)
#%%
import numpy as np
import pandas as pd
import mglearn
from sklearn.model_selection import train_test_split
from sklearn.datasets.base import Bunch

idol_data = np.array([
    #韓国アイドル
    #t○ice(9レコード)
    [30, 164, 0, 0], # モ○
    [35, 166, 0, 0], # サ○
    [27, 162, 0, 1], # ジ○ョウ
    [31, 159, 0, 0], # ダ○ョン
    [38, 163, 0 ,1], # ナ○ン
    [25, 169, 0, 1], # ジ○ンヨン
    [34, 170, 0, 1], # ツ○ィ
    [35, 159, 0 ,1], # チ○ヨン
    [35, 163, 0 ,1], # ミ○
    #iz○ne(12レコード)
    [40, 169, 0, 1], # チ○ン・ウォニョン
    [35, 163, 0, 1], # 宮○咲良
    [50, 160, 0, 1], # チ○・ユリ
    [55, 163, 0, 1], # チ○・イェナ
    [40, 169, 0 ,1], # ア○・ユジン
    [30, 150, 0, 0], # 矢○奈子
    [45, 160, 0, 1], # ク○ン・ウンビ
    [50, 163, 0 ,0], # カ○・へウォン
    [45, 158, 0 ,0], # 本○仁美
    [45, 164, 0 ,0], # キ○・チェウォン
    [45, 166, 0 ,1], # キ○・ミンジュ
    [45, 165, 0, 1], # イ・チ○ヨン

    #乃○坂46(20レコード)
    [30, 159, 0, 1], # 西○七瀬
    [35, 156, 0, 0], # 井○小百合
    [45, 155, 0, 1], # 星○みなみ
    [35, 164, 0, 0], # 松○沙友理
    [45, 162, 0, 1], # 白○麻衣
    [45, 163, 0, 0], # 衛○美彩
    [45, 157, 0, 1], # 岩○蓮加
    [45, 158, 0, 1], # 齋○飛鳥
    [35, 154, 0, 0], # 秋○真夏
    [40, 160, 0, 1], # 生○絵梨花
    [50, 155, 0, 0], # 桜○玲香
    [50, 162, 0, 1], # 高○一実
    [35, 158, 0, 0], # 中○花奈
    [40, 166, 0, 0], # 伊○純奈
    [55, 158, 0, 1], # 北○日奈子
    [50, 163, 0, 0], # 佐○木琴子
    [45, 165, 0, 1], # 新○眞衣
    [50, 152, 0, 1], # 与○祐希
    [45, 159, 0, 0], # 山○美月
    [55, 156, 0, 1], # 大○桃子

    #ハリウッド女優(19レコード)
    [40, 157, 0, 0], # ク○スティーナ・ミリアン
    [45, 157, 0, 0], # アナ・ケン○リック
    [50, 159, 0, 0], # ア○ンダ・サイフリッド
    [35, 160, 0, 0], # スカーレット・ヨ○ンソン
    [50, 164, 0, 0], # ジェ○ファー・ロペス
    [45, 165, 0, 1], # エ○・ワトソン
    [45, 168, 0, 1], # ペ○ロペ・クルス
    [35, 168, 0, 1], # メ○ル・ストリープ
    [45, 169, 0, 1], # アン○ェリーナ・ジョリー
    [40, 170, 0, 0], # 菊○凛子
    [40, 169, 0, 1], # ジ○シカ・アルバ
    [45, 174, 0, 0], # キ○メロン・ディアス
    [45, 173, 0, 1], # ミラ・ジョ○ォヴィッチ
    [50, 175, 0, 0], # ジェ○ファー・ローレンス
    [50, 175, 0, 0], # ミ○ンダ・カー
    [35, 177, 0, 0], # シャー○ーズ・セロン
    [50, 178, 0, 0], # ブ○イク・ライブリー
    [45, 180, 0, 0], # ユ○・サーマン
    [50, 180, 0, 0], # ニ○ールキッドマン
])

※データセットはnumpy配列です。
※髪の長さは「パッと見これくらいかな」という、完全なる概算レベルです。
※髪の色は、ググって最初に出た画像をもとに設定しています。

次に、上記の特徴量に対応するグループを定めます。

# 0=韓国アイドル, 1=乃○坂46, 2=ハリウッド女優
idol_target = np.array([
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
])

例えば、「特徴量:西野○瀬さん→グループ:乃木○46」って感じです。

それぞれの特徴量の名前やグループ名も設定しておきます。

feature_names = np.array([
    'hair length (cm)',
    'height (cm)',
    'eye',
    'hair color'
])

target_names = np.array(
    [
        '韓国アイドル',
        '乃○坂46',
        'ハリウッド女優'
    ], dtype='<U10'
)

次に、データの型をBunchに変換します。
Bunchはsklearnでよく見るデータの型です。

idol_dataset = Bunch(
    data = idol_data,
    target = idol_target,
    feature_names = feature_names,
    target_names = target_names
)

実装②プロット

4つの特徴量(髪の長さ、身長、目、髪の色)を、2つずつプロットしてみます。

# X_trainのデータからDataframeを作る
# idol_dataset.feature_namesの文字列を使ってカラムに名前をつける
idol_dataframe = pd.DataFrame(X_train, columns = idol_dataset.feature_names)

# データフレームからscatter matrixを作成し、y_trainに従って色を付ける
grr = pd.scatter_matrix(idol_dataframe, c=y_train, figsize=(15, 15), marker='0',hist_kwds={'bins': 20}, s=60, alpha=.8, cmap=mglearn.cm3)

f:id:snoopy_no_sora:20181210234925p:plain 見事に傾向がわからないプロットになってしまいましたが、気にしません。

実装③モデル選定とトレーニング(訓練)

傾向がよくわからないので、今回のモデルは最も基本的なk-最近傍法(KNeighborsClassifier)を用います。

from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors = 1)

# トレーニングフェーズ
knn.fit(X_train, y_train)

定義したknnに、X_trainとy_trainを読み込ませて訓練します。

実装④新しいデータで予測と、精度測定

X_newで新しいデータを作り、③で訓練した結果得られたモデルに予測させます。

#新しいデータ
#堀○央奈さん、乃○坂46
X_new = np.array([[35, 160, 0, 1]])

#種類を予測する(=prediction)
prediction = knn.predict(X_new)
print('Prediction:\n{}'.format(idol_dataset['target_names'][prediction]))

得られた結果がどの程度正しいかわからないので、テストデータをもとに精度を確かめます。

# 精度を測定
y_pred = knn.predict(X_test)
print('Test set score: {:.2f}'.format(np.mean(y_pred == y_test)))

f:id:snoopy_no_sora:20181210235244p:plain

はい、見事に外しました。
精度も60%…
(逆に60%もあることがびっくり)

実装してみて

今回のテーマは機械学習ということで、データセットを作り、モデルを作ってみました。
本当はどんなデータを特徴量として含めるかを検討すべきなのですが、今回は新卒2人のアイディアベースでデータセットを作りました。
まあ、結果見事に外れてしまいましたが(汗)

しかし、特徴量をよく検討し、データサンプルをもっと多くしたら精度の高いモデルもできそうだなと。

肝心の新卒2人は、かなり前のめりで取り組んでくれました。
やはり興味ある分野から実際に手を動かしてやってみるのが一番です。
機械学習の雰囲気は掴んでくれたみたいなので、次からは実践です。

新卒2人が機械学習を面白がってくれてよかったです。

(渡邊)