u++の備忘録

「ベースボールデータハッカソン」エンジニアリング部門で準優勝しました

昨日と本日の2日間にわたって開催された「パ・リーグ×パーソル ベースボールデータハッカソン」にて、エンジニアリング部門で準優勝しました。

techplay.jp

賞品として、パリーグ6球団タオルセットを頂きました。ありがとうございました。

f:id:upura:20181007222550j:plain

本記事では、ハッカソンの概要や私が取り組んだことなどをまとめます。外部に公開できない情報などの問題で理解が難しい部分があるかもしれませんがご了承ください。ご質問いただければ可能な範囲で対応いたします。

ハッカソンの概要

1日目の朝10時にデータが公開され、19時までに以下の2つから参加する部門を選択する形式のハッカソンでした。

  • データから予測精度を競う「エンジニアリング部門」
  • データから新しい発見を導き出す「コンサルティング部門」

今回は全32名が参加し、うち26名がエンジニアリング部門、6名がコンサルティング部門を選択しました。チーム参加も可能で、私は友人と3人チームでエンジニアリング部門を選びました。

エンジニアリング部門では、予想精度の高い上位4チームが予測手法などに関してプレゼンしました。(プレゼン内容自体は順位に関係なく、純粋に予測精度だけで順位が決まりました)

コンサルティング部門では、提出したプレゼン資料を基に選抜された上位2チームがプレゼンし、最優秀チームを決めました。

エンジニアリング部門の課題

エンジニアリング部門の課題は、「ファンクラブ会員が特定の試合に来るか否か」の予測でした。

約14万人分のうち半分の7万人についてはgame1〜45に来場したか否かの情報が、残りはgame1〜42に来場したか否かの情報が公開されました。ここで「隠されたgame43〜45に来場するか否かの値を予測する」という課題です。

f:id:upura:20181007211455p:plain

ファンクラブのマーケティングに関する情報以外に、今回は「ベースボールオペレーション」のデータが公開されたのが特徴的でした。

  • 各打者の試合ごとの個人成績
  • 各投手の試合ごとの個人成績
  • 各試合の打席ごとの結果

これらの野球のプレイデータをどのようにして来場予測に繋げるか、がハッカソンの鍵となりました。

また外部データの使用は禁止されていました。

f:id:upura:20181007212059p:plain

部門の選択

まず、データを探索的に分析しながら2つの部門のどちらに出すかを考えました。

実のところ、当初はメンバー的に強みがあるコンサルティング部門へ参加するつもりでした。しかし、下記の理由で最終的にはエンジニアリング部門への参加を決めました。

  1. 最初に立てた仮説と真逆の分析結果が出たため、チームで納得行く解釈ができなかった
  2. バックアップとして進めていたエンジニアリング部門の予測の精度がそこそこ良さそうだった

特徴量生成と予測モデル

今回、game43とgame44&45で予測方法を分割して考えました。その理由は下記の通りです。

game43〜45の来場情報が公開された7万人のうち、それぞれ何人が来場しているかを分析したところ、概ね以下のような結果になりました。

  • game43 → 7万人中5000人
  • game44 → 7万人中1000人
  • game45 → 7万人中1500人

game1〜42についても同様の分析をしたところ、ほとんどは14万人中1万人以上(つまりは7万人中5000人以上)の結果が出ていました。game44&45は過去のデータと比べて極端に数字が少ないため、過去のデータを基に予測モデルを作成しても上手くいかないと考えました。

3人の主な役割としては、game43の予測モデルを私が、game44&45を他2人のチームメンバーが担当しました。

game43について

  • 特徴量
    • ファンクラブ会員が「今季初めて参加した試合」のプレイデータの情報
  • 予測モデル

私のチームが作った特徴量として独自性があったのは、ファンクラブ会員が「今季初めて参加した試合」のプレイデータの情報だと思います。

ファンクラブ会員が(特定の試合に限らず)来場するか否かは、今季初めて参加した試合での「良質な体験」が利いてくると仮説を立てました。良質な体験とは「得点がたくさん入る」「ホームランがたくさん出る」「奪三振が多い」などを指します。

どういうものが良質な体験かを考えるのは機械学習に任せるのが良いと思考停止で思ったので、「ベースボールオペレーション」の3データについてそれぞれpandasのgroup byで大量に特徴を作成しました。

あとは勾配ブースティング分類器に突っ込み、ハイパーパラメータを調整しアンサンブルといった流れです。

game44&45について

上述した通り、game44&45は来場者が非常に少ないことが予想されます。さらに、過去のデータを活用した予測モデルの作成は困難でした。

そこで、無理に来場を予測することで精度を下げるリスクは取らず、「過去全試合に来場している人」など絶対に来そうな人だけを人力で確認する方針を取りました。具体的には7万人のうち、ほぼ全員を来場しないと予測し、5人だけを来場と予測しました。

予測対象の3分の2に当たるgame44&45のデータについて「機械学習を全く使わない」という戦略は、プレゼンで結構ウケました。無理に機械学習に頼らず人力に頼るのが大切な場面もあるなと感じました。


感想

率直な感想として、野球という自分が関心を持っているデータを触れるのは純粋に楽しかったです。

上位4チームに入りプレゼンができたこともあり、懇親会では多くの方と交流できました。こちらも実りある体験でした。プレゼンを多くの方に褒めていただき「データ分析を楽しんでいるのが伝わってきました」と言ってもらえたのが非常に嬉しかったです。

今回、game43の予測には機械学習を、game44&45では人間の力を大いに活用しました。イベントに関連したパネルディスカッションの中で「Data drivenとKnowledge drivenの関係性」のような話がありましたが、課題に応じて両者を適切に使い分けるのが大事だなと改めて実感する機会になりました。

最後に順位について。2位という結果は満足できるものではありますが、勝ち切ることができなかった経験を糧に今後も邁進していきたいと思います。

これからもデータ分析を楽しみながら、精進していきたいです。

技術書典5で弊社の機械学習活用事例を紹介します

2018年10月8日に池袋サンシャインシティで開催される技術書典5に、弊社のエンジニア有志で執筆した書籍を頒布します。

techbookfest.org

私は第1章「機械学習を用いた日経電子版Proのユーザ分析」を担当しました。

私は弊社にて、営業・マーケティング向けのデータ分析や、業務効率化のための環境整備を担当しています。

本章では、機械学習を用いた「日経電子版Pro」のユーザ分析事例を紹介しました。課題設定から始め、データの前処理や予測モデルの構築など一連の過程を、Pythonのコードと合わせて掲載しています。

pr.nikkei.com

以下のような読者を想定して執筆しました。Kaggleでテーブルデータを処理するような過程が含まれているので、Kaggleに興味がある方なら楽しんでお読みいただける内容になっていると考えています。

  • データ分析に興味がある
  • PythonのPandasを使ったことがある
  • データアナリストが実際に会社でどんなことをやっているか知りたい

場所は「き18」です。当日は私も売り子をやるので、ぜひブースまでお越しください!
※ 弊社の規定で決済方法は「かんたん後払い」のみとなります。お手数ですが事前にご準備いただければ幸いです。

↓よろしければ、はてなブックマークや拡散をお願いしますm(_ _)m

【Mac, 2018】pyenv/minicondaでのpytorch利用環境構築のメモ

『現場で使える!PyTorch開発入門 深層学習モデルの作成とアプリケーションへの実装』に取り組むに当たって、自分なりの環境構築のメモ。
www.shoeisha.co.jp

仮想環境の構築

mkdir pytorch-practice
cd pytorch-practice
python -m venv env
source env/bin/activate

minicondaのインストール

pyenv install miniconda-latest
pyenv local miniconda-latest

パッケージのインストール

conda install pandas jupyter matplotlib scipy scikit-learn pillow tqdm cython
conda install pytorch=0.4 torchvision -c pytorch//
pip install flask smart_getenv gunicorn
conda install -c caffe2 caffe2 protobuf
sudo apt install git build-essential g++ cmake

確認

f:id:upura:20180923122731p:plain

import numpy as np
import torch
t = torch.tensor([[1, 2], [3, 4.]])
t

【Mac, 2018】pyenv/minicondaでのpytorch利用環境構築のメモ

www.shoeisha.co.jp

『現場で使える!PyTorch開発入門 深層学習モデルの作成とアプリケーションへの実装』に取り組むに当たって、自分なりの環境構築のメモ。

仮想環境の構築

mkdir pytorch-practice
cd pytorch-practice
pyenv -m venv env
source env/bin/activate

minicondaのインストール

pyenv install miniconda-latest
pyenv local miniconda-latest

パッケージのインストール

conda install pandas jupyter matplotlib scipy scikit-learn pillow tqdm cython
conda install pytorch=0.4 torchvision -c pytorch//
pip install flask smart_getenv gunicorn
conda install -c caffe2 caffe2 protobuf
sudo apt install git build-essential g++ cmake

確認

f:id:upura:20180923122731p:plain

import numpy as np
import torch
t = torch.tensor([[1, 2], [3, 4.]])
t

【論文メモ】Neural Networkを用いた特徴量の重要度の計算方法

Importance of Feature Selection for Recurrent Neural Network Based Forecasting of Building Thermal Comfort

概要

To select proper features tailored for particular network, we decided to use a well known sensitivity based method developed by Moody [4]. It is called Sensitivity based Pruning (SBP) algorithm. It evaluates a change in training mean squared error (MSE) that would be obtained if ith input’s influence was removed from the network. The removal of influence of input is simply modeled by replacing it by its average value.

  • 特徴を一つずつ外した時に全体の誤差がどの程度変化するかを見ることで重要度を見いだす手法
    • 木系のモデルの特徴量の重要度の計算方法と似たアイディア

Pythonで動く形態素解析ツール「nagisa」を使ってみた

はじめに

PyCon2018でポスター展示があったらしく、フォロワーさんの投稿で存在を知りました。


使ってみた

インストールはこれだけ。

pip install nagisa

簡単に形態素解析ができます。

>>> import nagisa
[dynet] random seed: 1234
[dynet] allocating memory: 32MB
[dynet] memory allocation done.

>>> text = 'pythonで手軽に使えるツールです'

>>> words = nagisa.tagging(text)

>>> print(words)
python/名詞 で/助詞 手軽/形状詞 に/助動詞 使える/動詞 ツール/名詞 です/助動詞

>>> print(words.words)
['python', 'で', '手軽', 'に', '使える', 'ツール', 'です']

>>> print(words.postags)
['名詞', '助詞', '形状詞', '助動詞', '動詞', '名詞', '助動詞']

nagisaの利点

文字単位の双方向LSTMを採用しており、URLや顔文字に頑健

>>> text = 'ブログのURLはhttps://upura.hatenablog.com/です'

>>> words = nagisa.tagging(text)

>>> print(words.words)
['ブログ', 'の', 'URL', 'は', 'https://upura.hatenablog.com/', 'です']

ちなみに、MeCabMeCab.Tagger("-Owakati") を使うと、URLの中身がバラバラに分割されてしまいます。

>>> import MeCab

>>> t = MeCab.Tagger("-Owakati")

>>> result = t.parse(text)

>>> print(result)
ブログ の URL は https :// upura . hatenablog . com / です

単語分割の方法を調整できる

辞書にない固有名詞は、形態素解析ツールを使うと一般に過度に分割されます。

>>> text = '日本経済新聞を読んでいます'
>>> words = nagisa.tagging(text)
>>> print(words.words)
['日本', '経済', '新聞', 'を', '読ん', 'で', 'い', 'ます']

この時の辞書の登録方法もお手軽です。

>>> new_tagger = nagisa.Tagger(single_word_list = ['日本経済新聞'])

>>> words = new_tagger.tagging(text)

>>> print(words.words)
['日本経済新聞', 'を', '読ん', 'で', 'い', 'ます']

nagisaの課題

上記の資料によると、解析速度に課題があるとのことです。

f:id:upura:20180918203247p:plain

おわりに

インストールが簡単で手軽に使えるので、速度を必要としない解析の際には便利だと思いました。

ランダムフォレストなど木系のアンサンブルモデルの解釈性を高める「Feature Tweaking」

はじめに

今回は、ランダムフォレストなど木系のアンサンブルモデルの解釈性を高める「Feature Tweaking」について紹介します。Pythonによる実装や使い方をGitHubにて公開しています。

手法の概要

機械学習アルゴリズムは世間一般で「ブラックボックス」だと評されますが、解釈性に関する研究も盛んになっている印象があります。今回紹介する「Feature Tweaking」はKDDという著名な国際会議に2017年に採択された論文で提唱された手法で、著者はYahoo!Facebookに所属しています。

Tweakingは日本語で「微調整」の意です。「Feature Tweaking」は、木系のアンサンブルモデルの予測結果を変える方向に、入力 xを微調整します。「入力 xの中のどの変数をどう改善すれば良いかが分かる」といった意味で、解釈性が高まるといった具合です。

著者による紹介動画

www.youtube.com

日本語文献

今回の実装・記事執筆に当たって、下記2つの日本語の資料・記事を参照しました。

www.slideshare.net
setten-qb.hatenablog.com

特に後者の記事では既にPythonによる実装が公開されており、非常に参考になりました。上記で公開した私のGitHubは、こちらの記事に多少の修正と説明を加えたものになります。実装内容の理論的な概要については、こちらの記事をご参照ください。

I fixed some codes and added some explanations:

  • Fix load_iris() to datasets.load_iris() at In [2]
  • Fix rfc.fit(x, y) to rfc.fit(x_arr, y_arr) at In [3]
  • Fix aim_label = 3 to aim_label = 2 at In [7] and [22]
  • Add the usage of feature_tweaking()
  • Add featureTweakPy.py to extract functions

Quoted from featureTweakPy/README.md

「featureTweakPy」の使い方

今回、GitHubでは以下のような形で関数を読み込めるような形式にしました。

from featureTweakPy import feature_tweaking

以降、具体的な使い方を流れに沿って紹介します。

Requirements

Python 3系を使ってください。以下のパッケージを利用します。

  • numpy
  • pandas
  • scipy.stats

Download

git clone して、当該フォルダに移動します。上記で示したパッケージのインストールが必要な場合は適宜 pip install などをお願いします。

git clone git@github.com:upura/featureTweakPy.git
cd featureTweakPy

Package import

最初に、必要なパッケージをインポートします。今回は木系のアンサンブルモデルとしてランダムフォレストを、データセットとしては有名なアヤメを利用します。

import numpy as np
from sklearn import datasets
from sklearn.ensemble import RandomForestClassifier

from featureTweakPy import feature_tweaking

iris = datasets.load_iris()
x_arr = iris['data']
y_arr = iris['target']

Random Forest Prediction

「Feature Tweaking」は木系のアンサンブルモデルの予測結果を微調整する手法なので、まずは普通にモデルを学習させておく必要があります。

rfc = RandomForestClassifier()
rfc.fit(x_arr, y_arr)

Using function()

まずはハイパーパラメータの設定です。

Hyper Parameters Setting

アヤメのデータセットは3種類のラベルがあり、今回はそのうち2の付いたラベルに変化する方向に微調整させたいと思います。

class_labels = [0, 1, 2] 
aim_label = 2
epsilon = 0.1
Cost Function Setting

この手法では最も「コスト」が小さいような微調整方法を探索するので、何を「コスト」とするか定義する必要があります。コスト関数として今回は、単純にユークリッド距離を採用しました。他にもコサイン距離などが想定できます。

def cost_func(a, b):
    return np.linalg.norm(a-b)
Sample Data for Demonstration

いよいよ feature_tweaking() 関数を使います。

x = x_arr[0]
x
array([5.1, 3.5, 1.4, 0.2])
x_new = feature_tweaking(rfc, x, class_labels, aim_label, epsilon, cost_func)
x_new
array([5.1       , 2.9999999 , 4.75000038, 0.90000001])

微調整された x_new を元々の x と比べると、第一成分では変更がなく、それ以外の要素では値が変わっていると分かります。この方向に微調整すると定義した枠組みの中で最適なコストでランダムフォレストの予測結果を目的のラベル方向に変化させられるということです。

ここで、著者による紹介動画でも言及されていますが、今回の手法は「あくまでアンサンブルモデルの中の個々の決定木の結果を改善している」に過ぎず、必ずしも「ランダムフォレストとしての予測結果が目的のラベルに変わる」というわけではないことには注意が必要です。

f:id:upura:20180918193744p:plain

おわりに

ランダムフォレストをはじめとした木系のアンサンブルモデルは、手軽に高精度な予測結果を得られることから、特にテーブルデータを扱う際に頻繁に利用されています。

活躍の場はKaggleだけでなく広範に渡りつつあるかと思いますが、特にビジネスにおいては単に高精度を出すだけではなく、予測から得られた知見をどのように活用するかも同様に重要です。この手法は少し間接的な気もしますが、木系のアンサンブルモデルの解釈性を高められるという意味で、大きな価値があると思いました。