u++の備忘録

データサイエンティストが活躍する系の映画をオススメしてもらった

私のtwitterでのしょうもない呟きに思いの外たくさんのリプライを頂戴したので、自分用の整理として推挙された映画をまとめます。広範な意味でのデータサイエンスを扱う映画も含まれていると思います。

既に観た映画

次の3作品は、既に私が鑑賞済の映画です。

マネーボール』(2011)


メジャーリーグの貧乏球団アスレチックスを、常勝軍団に作り変えた男ビリー・ビーン
野球の常識を覆し球史に刻まれた「マネーボール理論」が起こした奇跡。完全映画化!

『マネーボール』予告編 - YouTube

イミテーション・ゲーム/エニグマと天才数学者の秘密』(2014)


第2次世界大戦時、ドイツの世界最強の暗号エニグマを解き明かした天才数学者アラン・チューリングの波乱の人生を描いた伝記ドラマ。劣勢だったイギリスの勝利に貢献し、その後コンピューターの概念を創造し「人工知能の父」と呼ばれた英雄にもかかわらず、戦後悲劇の運命をたどったチューリングを、ベネディクト・カンバーバッチが熱演する。

映画『イミテーション・ゲーム/エニグマと天才数学者の秘密』予告編 - YouTube

アルキメデスの大戦』(2019)


1933年(昭和8年)、戦艦大和の建造をめぐる“机の上の大戦”が始まる。
これは、帝国海軍という巨大な権力に立ち向かい、数学で戦争を止めようとした男の物語。

映画『アルキメデスの大戦』予告【7月26日(金)公開】 - YouTube

ネタバレ要素を含みますが、以下に鑑賞録を記しています。

upura.hatenablog.com

オススメしてもらった映画

『NUMBERS 天才数学者の事件ファイル』(2005)

www.happyon.jp

犯罪者の行動を予測する公式を作る天才数学者の弟の協力で、さまざまな難しい犯罪を解明するFBIエージェントを描くドラマシリーズ。

NUMBERS 天才数学者の事件ファイル が見放題! | Hulu(フールー) 【お試し無料】

『ミッション: 8ミニッツ』(2011)


列車爆破事故の犯人を見つけるべく、犠牲者が死亡する8分前の意識に入り込み、爆破直前の列車内を追体験していく男の運命を描く。困難なミッションを課せられた主人公を、『ブロークバック・マウンテン』のジェイク・ギレンホールが熱演。巧妙に練り上げられたプロットと先の読めないストーリー展開に引き込まれる。

映画『ミッション:8ミニッツ』特報 - YouTube

エクス・マキナ』(2014)


人間と人工知能が繰り広げる駆け引きを、限られた登場人物と舞台設定や目を引くビジュアルで活写する。

映画『エクス・マキナ』予告編 - YouTube

『ドリーム』(2016)


2017年 第89回アカデミー賞3部門(作品賞、助演女優賞、脚色賞)ノミネート
宇宙開発史上の偉業を支え、新しい時代を切り開いた知られざる3人の女性がいた――

映画『ドリーム』予告A - YouTube

『メッセージ』(2016)


ある日突然、巨大飛行体が地球に。
その目的は不明―
未知なる飛行体が突如出現、彼らは人類に何を伝えようとしているのか?

映画『メッセージ』本予告編 - YouTube

『スノーデン』(2016)


米国最大の機密を暴いた男。彼は、英雄か。犯罪者か―。
元CIA職員エドワード・スノーデンの知られざる人物像に迫るヒューマンドラマ。

映画『スノーデン』 予告編 - YouTube

「Sports Analyst Meetup #4」を開催&LTしました #spoana

はじめに

「Sports Analyst Meetup #4」を開催しました。前回に引き続き、自分自身もLTで発表しました。

spoana.connpass.com

発表資料

発表資料はこちらにまとまっています(今後、資料が公開され次第追加していきます)。

spoana.connpass.com

togetter

Twitterの #spoana タグの付いた投稿は、下記にまとめています。

togetter.com

ロングトーク①高久侑也さん(株式会社Sportip)

  • Sportip*1のCEOを務める高久さんによるお話でした
  • Sportipは、競技者の動きや姿勢など個人のデータを収集・分析できるような仕組みを提供しています
  • デモも含めて、Sportipの取り組みやビジョンなどを語っていただきました

なお今回の会場は、Sportipが入居しているNTTドコモベンチャーズ*2にご提供いただきました。ありがとうございました。

ロングトーク② TKB84さん

  • 「スポーツ分析業界に飛び込んで半年で見えてきた、現状の概観と今後の展望」という題目での発表でした
  • スポーツ分析業界で実際に働き始めたTKB84さんに、ご自身の経歴や現状の分析、そして「今後どのような人材が求められるか」という展望などの生々しい話も含めて語っていただきました。

LT

今回もどれも面白い12本のLTが実施されました。LTの内容については、発表資料やtogetterをご参照ください。

自分の発表

私の発表は、以前にブログで公開した内容*3*4*5*6をまとめたものです。GitHub*7で実装も公開しています。

おわりに

第4回は数理系な話が多く、個人的な満足度が高い回となりました。また以前の登壇の反響をご共有くださった方や、自分の第3回での発表*8を追加検証してくださった方もいて、一定回数を重ねてきたことを実感した場面も多かったです。参加してくださった皆さま、ご登壇してくださった皆さま、会場をご提供いただいたSportipとNTTドコモベンチャーズの皆さまに、改めて御礼申し上げます。

テーブルデータ向けのGAN(TGAN)で、titanicのデータを増やす

はじめに

ynktk さんのツイート*1を見て、テーブルデータ向けの GAN の存在を知りました。本記事では、TGAN を用いて titanic のデータを拡張してみます。

TGANとは

テーブルデータに対応した GAN (Generative Adversarial Network, 敵対的生成ネットワーク) *2 です。数値などの連続変数だけではなく、カテゴリ変数にも対応しています。

Titanic のデータを増やす

今回は、著名なデータセットである Titanic のデータを対象にTGANを試します。

データの読み込み

まずはデータを読み込みます。データは Kaggle からダウンロードしました*3。下図のようなデータが格納されています。

df = pd.read_csv('input/train.csv')
df.head()

f:id:upura:20190820092059p:plain

行数は900弱です。

df.shape
(891, 12)

欠損値の削除

TGANは、欠損値に対応していません。最初に各カラムの欠損値の数を確認しておきます。

df.isnull().sum()
PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age            177
SibSp            0
Parch            0
Ticket           0
Fare             0
Cabin          687
Embarked         2
dtype: int64

欠損値が大半を占める 'Cabin' は、この段階で削除します。合わせて、GANでの増幅に不適切な ['PassengerId', 'Name', 'Ticket'] も削除しておきます。

df.drop(['Cabin', 'PassengerId', 'Name', 'Ticket'], axis=1, inplace=True)

その他の欠損値を含む2カラムについて、'Age' は平均値を四捨五入して整数にした値、'Embarked' は最頻値である 'S' で埋めました。

df['Age'].fillna(round(df['Age'].mean(), 0), inplace=True)
df['Embarked'].fillna(df['Embarked'].value_counts().index[0], inplace=True)

カラム名の保持

現在 PyPI でインストールできる TGAN (ver 0.1.0) には、実行後に DataFrame のカラム名がインデックス番号に置換されてしまう不具合があります*4。そのため、実行後のために事前にカラム名を変数に入れて保持しておく必要があります。

df_columns = df.columns

連続変数の指定

TGAN の実行時には、連続変数のカラムのインデックス番号一覧をリスト型で渡します。今回は、次のように float 型のカラムを抽出しました。

continuous_columns = [df.columns.get_loc(c) for c in df.select_dtypes(include=['float']).columns]

TGAN の実行

いよいよ TGAN を実行します。

from tgan.model import TGANModel
tgan = TGANModel(continuous_columns, batch_size=50)
tgan.fit(df)

このときdocsには記載がありませんが、小さめのbatch_sizeを引数に指定しないと、tensorpack の assertion error *5で実行が止まってしまいます。

実行時間は、900弱のデータセットで15分程度でした。学習済のモデルは、次のように保存可能です。

model_path = 'output/models/mymodel.pkl'
tgan.save(model_path)

サンプルの抽出

学習済のモデルから、次のようにデータを生成できます。今回は、元のデータセットと同数を指定しました。

num_samples = len(df)
samples = tgan.sample(num_samples)

f:id:upura:20190819161132p:plain

'Age' が小数点以下になっているので丸める処理などは必要かもしれませんが、'Sex' などカテゴリ変数も含めてデータが生成できていると分かります。目的変数である 'Survived' も、問題なく増幅されていました。

samples['Survived'].value_counts()
0    540
1    310

おわりに

本記事では、TGAN を用いて titanic のデータを拡張してみました。Kaggle などの文脈で言うと、学習用データの水増しに利用できる可能性があります。ただし、ynktk さんとも議論した通り*6、GAN でまともなデータを作るにはそもそも十分量のデータセットが必要というジレンマがありそうです。

TGAN で増やしたデータで性能が向上するかはデータセットと課題設定次第ですが、機会があれば試してみても面白いなと思いました。

今回の実装は GitHub *7で公開しています。

*1:

*2:papers.nips.cc

*3:www.kaggle.com

*4:github.com

*5:github.com

*6:

*7:github.com

【ネタバレ有】『アルキメデスの大戦』とデータ分析の仕事

はじめに

OsciiArtさんの下記のツイートで興味を持ち、観に行きました。本記事では、ネタバレ要素を含みつつ、徒然と感想を書いていこうと思います。


あらすじ

事前の触れ込み通り、まさに「データ分析」を題材にした映画で、主人公の天才数学者・櫂直が旧態依然の組織の中で奮闘します。

時は1933年、海軍では巨大戦艦の建造を巡った対立が発生していました。来たる戦争に向けて華美な巨大戦艦を建造したい「建造推進派」と、新世代の海戦を見据え機動力のある航空母艦を推す「建造反対派」です。

旧態依然な文化が根強く残る海軍の中では「建造推進派」が優勢でした。2週間後の最終決定の会議までに状況を覆したい山本五十六ら「建造反対派」は、巨大戦艦の建造費が過剰に小さく見積もられていると感じた点に目をつけました。

山本五十六は天才数学者の主人公に、巨大戦艦の建造費の正確な見積もりを依頼。しかし、主人公は戦艦のドメイン知識もなく、今回建造予定の巨大戦艦の詳細情報もありません。そのような中で付け焼き刃ながらドメイン知識を身につけ、地道な情報収集も重ねていきます。

「建造推進派」による数々の妨害にも屈せず、巨大戦艦の建造費の予測値を算出した主人公。予測値を突きつけられた「建造推進派」の反応、そして巨大戦艦の建造の顛末は・・・?

(続きは劇場で)

感想

「データ分析の能力を見込まれた主人公」=「データサイエンティスト」と見立てて、感情移入してしまいました。まずは「データ分析で課題が解決できそう」という目論見で呼び出されるも、使えるデータがほとんどない状況。ドメイン知識もない主人公が自ら様々な場所に足を運んでデータを収集し、少しずつ知見を得ていく姿は胸を打つものがあります*1

そして「建造推進派」による数々の妨害。主人公がデータを手に入れられないような政治的な根回しや、最終決定の会議の前倒しなど、フィクションでありながら妙なリアリティのある出来事*2が巻き起こります。「突然やってきた素人の主人公が成功したら困る」という理由で、「建造反対派」であるはずの設計士が主人公に非協力的な部分も、実に人間味にあふれて生々しかったです。

最後に、巨大戦艦の建造費の予測値を突きつける際の描写です。詳細部分は映画の根幹になってしまうので割愛しますが、如何に正しくても数式を押し付けるだけでは聴衆に響かない点や、数式を超越する物事の存在など、多くを考えさせられるクライマックスでした。

おわりに

本記事では、ネタバレ要素を含みつつ『アルキメデスの大戦』の感想を書きました。普段はこの類いの感想ブログはあまり書かないのですが、予想以上に感銘を受けたので筆を執ってしまいました。いつの間にか大人1枚1900円になった映画*3ですが、たまに観るのは悪くないなあと改めて感じました。

*1:自分もKaggleのコンペで自ら猫カフェに行ったことを思い出しました

*2:私はここまで酷い話は噂レベルでしか聞いたことないですが

*3:eiga.com

scikit-learn-contrib の Metric Learning を試す

Metric Learning について

Metric Learning は、データの教師情報を基にデータ間の距離や類似度などの Metric を学習する手法です。日本語で手軽に読める記事だと、*1, *2 などが詳しいです。

このたび、phalanx さんの tweet *3で、 Metric Learning の基礎的なアルゴリズムのいくつかが scikit-learn-contrib *4に搭載されていると知りました。

本記事では、scikit-learn-contrib の metric-learn パッケージを用いて、簡単にMetric Learning を試します。

インストール

README や PyPI *5 に記載のある通り、次の通りにインストールします。

pip install metric-learn

利用するデータセット

今回は、sklearn に含まれている load_digits データセットを利用します*6。64次元の特徴量・0-9の10種類のラベルを持つ手書き数字のデータセットです。

f:id:upura:20190818182045p:plain
画像は*7より引用。

可視化(Metric Learning 前)

特徴量の可視化に当たっては、T-SNE *8 を用いて2次元への削減を行います。

次のコードは、metric-learn の docs に掲載されていた内容*9を、凡例を出すように一部改変しています。

def plot_tsne(X, y):
    plt.figure(figsize=(8, 6))
    
    # clean the figure
    plt.clf()

    tsne = TSNE()
    X_embedded = tsne.fit_transform(X)

    cmap = plt.get_cmap("tab10")
    for idx in range(10):
        plt.scatter(X_embedded[(y==idx), 0], X_embedded[(y==idx), 1], c=cmap(idx), label=idx)

    plt.legend()
    plt.xticks(())
    plt.yticks(())

    plt.show()

load_digits データセットをそのまま可視化したところ、下図のようになりました。大まかに分かれてはいますが、中央付近など少し煩雑になっていると分かります。

f:id:upura:20190818180214p:plain

可視化(Metric Learning 後)

次に、Metric Learning を実施します。

import metric_learn


# setting up LMNN
lmnn = metric_learn.LMNN(k=6, learn_rate=1e-6)

# fit the data!
lmnn.fit(X, y)

# transform our input space
X_lmnn = lmnn.transform(X)

いくつかのアルゴリズムが実装されていますが、ここでは Large Margin Nearest Neighbor (LMNN) を採用します。

Algorithms

  • Large Margin Nearest Neighbor (LMNN)
  • Information Theoretic Metric Learning (ITML)
  • Sparse Determinant Metric Learning (SDML)
  • Least Squares Metric Learning (LSML)
  • Neighborhood Components Analysis (NCA)
  • Local Fisher Discriminant Analysis (LFDA)
  • Relative Components Analysis (RCA)
  • Metric Learning for Kernel Regression (MLKR)
  • Mahalanobis Metric for Clustering (MMC)

READMEから引用。

Metric Learning 実施後の特徴量を可視化したところ、下図のようになりました。Metric Learning 実施前よりも、各クラスがハッキリと分かれているのが確認できます。

f:id:upura:20190818180230p:plain

今回は全データで学習し、全データに適用しています。Metric Learning はデータ間の距離や類似度などの Metric を学習しているので、学習に用いていないデータセットに適用することが可能です。

例えば Kaggle のような教師あり機械学習の文脈で利用する場合には、train データセットで Metric を学習し、test データセットにも適用することになるでしょう。分離に適した新しい特徴量空間を用いることで、より分類性能が高いモデルの構築が期待されます。

おわりに

本記事では、scikit-learn-contrib の metric-learn パッケージに搭載されている Metric Learning を試しました。なかなか使い所が難しい印象もある技術ではありますが、選択肢の一つとして持っておく価値は多分にあると感じています。

実装は notebook 形式で GitHub にて公開しています*10

【特徴量の追加編】機械学習を用いた大相撲千秋楽の勝敗予想

はじめに

前回は、「Sports Analyst Meetup #4」でのLTに向けて、ベンチマークとなる機械学習モデルを構築しました。新しい特徴量を追加することで、予測モデルの性能が向上することも確認しました。

upura.hatenablog.com

本記事では、新しい特徴量を加えて、ベンチマークのLightGBMモデルの改善に挑戦します。

「連勝・連敗」特徴量の追加

千秋楽を迎えるに当たって、力士が何連勝・何連敗しているかを示す特徴量です。例えば9日に勝利した後で10〜14日に5連敗している場合は 'wins_till_final_day' が 0 で 'loses_till_final_day' が5になります。直感的には、千秋楽の勝敗に影響を与えそうな特徴量です。

def calc_wins_till_final_day(row):
    cnt = 0
    for i in range(14):
        if row.iloc[14 - i] == 1:
            cnt += 1
        else:
            return cnt
    return cnt


def calc_loses_till_final_day(row):
    cnt = 0
    for i in range(14):
        if row.iloc[14 - i] == 0:
            cnt += 1
        else:
            return cnt
    return cnt


df['wins_till_final_day'] = df.apply(calc_wins_till_final_day, axis=1)
df['loses_till_final_day'] = df.apply(calc_loses_till_final_day, axis=1)

この2つの特徴量を前回の機械学習モデル(CVスコアはAUC: 0.554915)に加えたところ、CVスコアはAUC: 0.561075に向上しました。feature importanceで見ると上から3, 4番目に登場してきています。

f:id:upura:20190808171307p:plain

testデータセットでの性能を見たところ、0.5を閾値にした場合の正答率と混同行列は次の通りに変化しました。

0.5476190476190477
→ 0.5561904761904762
array([[302, 218],
       [257, 273]])

→

array([[299, 221],
       [245, 285]])

tsfresh特徴量の追加

次いで、tsfreshという時系列特徴量を作成してくれるライブラリを利用します。勝敗の0, 1を時系列情報と見なし、特徴量を抽出する狙いがあります。

tsfresh.readthedocs.io

tsfreshの利用に当たって、dataframeを加工します。現在は1行ごとに列方向に勝敗を保持していますが、tsfreshでは縦方向にデータを保持する必要があります。

f:id:upura:20190803220932p:plain

df_list = []
for index, row in df.iterrows():
    _df = pd.DataFrame(row.iloc[1:15].T)
    _df.columns = ['results']
    _df['id'] = index
    df_list.append(_df)

df_tsf = pd.concat(df_list).reset_index(drop=True)
df_tsf['results'] = df_tsf['results'].astype(float)
df_tsf.head()

f:id:upura:20190810164537p:plain

あとは extract_features 関数を利用するだけで、800近くの特徴量を生成できます。今回は select_features 関数を利用し選定した9個の特徴量を利用しました。

from tsfresh import extract_features
extracted_features = extract_features(df_tsf, column_id='id')

f:id:upura:20190810164738p:plain

これらの特徴量を機械学習モデルに加えたところ、CVスコアはAUC: 0.5699616に向上しました。feature importanceで見ると、追加した特徴量が予測に寄与していると確認できます。しかし残念ながら、testデータセットでの性能は「連勝・連敗」特徴量を追加した時点を上回ることはありませんでした。

f:id:upura:20190810165506p:plain

おわりに

本記事では、ベンチマークとなる機械学習モデルに新しい特徴量を加えて、ベンチマークのLightGBMモデルの改善に挑戦しました。特徴量の追加を試した所感から言うと、LightGBMベースで特徴量を増やしていく方法には限界がありそうです。次回以降は、勝ち負けの「01111...」の流れをRNNに入れるなど、時系列的な特徴を加味した機械学習モデルを試してみたいと思います。

【書籍メモ】『データマイニングエンジニアの教科書』

データマイニングエンジニアの教科書』を読んだので、雑感を書きます。

www.c-r.com


書籍の概要

  • データマイニングエンジニアの教科書』
  • 著者:森下壮一郎・編著、水上ひろき/高野雅典/數見拓朗/和田計也・著
  • 出版社:シーアンドアール研究所 (2019/6/27)

以下は書籍紹介ページから引用。

本書は、プロとしてデータマイニングを行うための教養を身に付けるための1冊です。
データを分析するための知識を技術について、統計・エンジニアリング・ビジネス・倫理の基礎知識を解説しています。 データマイニングを始めようとしている人にオススメの1冊です。

目次は次の通りで、特にCHAPTER 11, 13など普通の技術書ではあまり扱わない話題を広範に掲載しています。

CHAPTER 01 データマイニングを始める前に
CHAPTER 02 統計学の基礎
CHAPTER 03 計算機上のデータ
CHAPTER 04 構造を持つデータ
CHAPTER 05 テーブル
CHAPTER 06 可視化
CHAPTER 07 パターンと距離
CHAPTER 08 多変量解析
CHAPTER 09 時系列解析
CHAPTER 10 計算量の見積もり
CHAPTER 11 エンジニア的財務会計
CHAPTER 12 指標を考える
CHAPTER 13 技術者倫理

所感

どの章も、端的に要点がまとまっています。全般に基礎的な内容を扱っている書籍なので、ある程度知っているトピックの場合は物足りない感は残ると思います。自分の場合は、サクサク読み流しながら、自分の知識の抜け漏れを確認するような使い方をしました。

精読したのは、CHAPTER 11「エンジニア的財務会計」から。昔に簿記3級を学んだ経験があるので、思い出しながらエンジニア向け書籍に会計の話題がある理由を噛み締めていました。

CHAPTER 12「指標を考える」は、個人的に一番好きな内容でした。「会社のビジネスを紐解いて指標に落とし込む」という自分が業務において常々意識している話が明文化されていて、統計や分析の手法だけでなく視野の広い話が掲載されている点で、本書への好感度が更に高まりました。

CHAPTER 13「技術者倫理」は、期せずしてタイムリーな話題でした。当たり前の内容が多かったですが、データを扱う人間として一読して改めて思いを馳せる良い機会となりました。

おわりに

本記事では、『データマイニングエンジニアの教科書』を紹介しました。単なる統計や分析の手法だけでなく、会計・指標・倫理などの話題も広範に扱っています。各トピックは基礎的な内容が掲載されている印象なので、前から目を通して気になった部分を重点的に学ぶような使い方もできそうです。網羅的に知識の確認ができる、良い本でした。