csv化で文字列になったlistやdictを元に戻す
配列が格納されているレコードを含む csv を df で呼び出すと配列の部分が str に変換されてしまうのですが、解決手段ないですか。。
— かえるるる | krrr (@kaeru_nantoka) September 3, 2019
csv化すると文字列になってしまう仕様があるのでpickle形式などで保存するのが良いですが、諸般の事情でcsvで読み込む想定の場合の一つの解決策として、ast.literal_eval() *1*2 を使う方法を紹介します。
具体例
冒頭でastとpandasをimportします。astは標準ライブラリに含まれているので、pip installなどは不要です。
import ast import pandas as pd
今回は次のような単純なDataFrameを題材にします。
df = pd.DataFrame({ 'sample': [[1, 2, 3], [4, 5, 6], [7, 8, 9]] }) df
要素を確認すると、list型になっています。
df['sample'][0], type(df['sample'][0])
([1, 2, 3], list)
このDataFrameを一旦csvに吐き出した後に改めて読み込むと、要素は文字列型に変換されています。
df.to_csv('sample.csv', index=False) df2 = pd.read_csv('sample.csv') df2['sample'][0], type(df2['sample'][0])
('[1, 2, 3]', str)
文字列を split() して分割する方法もありますが、ここでは ast.literal_eval() を使うことで list 型から文字列型に変換しました。ast.literal_eval() はdict型への変換にも対応しています。
df2['sample_list'] = [ast.literal_eval(d) for d in df2['sample']] df2
df2['sample_list'][0], type(df2['sample_list'][0])
([1, 2, 3], list)
Poincaré Embeddings でJ1リーグのチーム・選手を可視化
ふと「Poincaré Embeddings」*1で遊んでみたいと思い立ち、サッカーJ1リーグのデータで試してみました。
Poincaré Embeddings
Poincaré Embeddingsに関する説明は、ABEJA*2やscouty*3のブログに譲ります。
Poincaré Embeddings は端的に言うと word2vec の埋め込み先をユークリッド空間ではなく双曲空間にするという手法で、階層構造やべき分布をもつデータを埋め込むという問題設定において、低次元でもよい表現を与えられるという特徴があります。
gensimでの実装とデータセット
Poincaré Embeddingsを手軽に試すに当たって、gensimでの実装*4が存在します。
この実装に渡すデータセットの形式は次の通りです。データセットはタプルを要素に持つリスト形式で、各タプルは('選手名', 'チーム名')のような関係性を持っています。
[('アウグスト ペドロ デ ソウザ', '鹿島アントラーズ'), ('アウグスト ペドロ デ ソウザ', '川崎フロンターレ'), ('アジエル アモリム', '湘南ベルマーレ'), ('アジエル アモリム', '浦和レッズ'), ('アデミウソン', '横浜F・マリノス'), ('アデミウソン', 'ガンバ大阪'), ('アドリアーノ フェヘイラ', 'セレッソ大阪'), ('アドリアーノ フェヘイラ', 'ガンバ大阪'), ('アマラオ', 'FC東京'), ('アマラオ', '湘南ベルマーレ')]
一般にこのような形式で存在しているデータセットはさほど多くなく、今回も全工程の中で特にデータセットを作る部分に苦心しました。
やりたいこと、そのものズバリのWebサイトを見つけた。完全なる優勝🏆⚽️
— u++ (@upura0) August 28, 2019
今回は「J1リーグの各チームの歴代所属選手の可視化」という題材に落とし込むことで、Poincaré Embeddingsに適した階層構造を持つデータセットを準備できました。収集には「FootballGEIST」*5を利用しています。具体的には、J1リーグ全18チームそれぞれの歴代所属選手のページからデータを収集し、gensimの実装に渡せる形式にpandasで加工しました。
Poincaré Embeddingsの学習
パッケージのインポートをします。ここでplotlyのバージョンが3以上だと可視化の際にエラーが出ます*6。
from gensim.models.poincare import PoincareModel from gensim.viz.poincare import poincare_2d_visualization from IPython import display from plotly.offline import init_notebook_mode, iplot import pandas as pd init_notebook_mode(connected=True)
環境に入っているバージョンを確認し、必要ならば2.7.0辺りのバージョンを入れておきます。
# import plotly # plotly.__version__ # '2.7.0' !pip install plotly==2.7.0
先の節で用意したデータセットを用いて、Poincaré Embeddingsの学習を実行します。今回の場合、epochsは2000回程度で十分なようでした。
model = PoincareModel(train_data, size=2, negative=8) model.train(epochs=5000)
次のコードでplotlyでの可視化を実行できます。show_node_labelsにはラベルを付ける項目を指定します。
relations_set = set(train_data) figure_title = '' iplot(poincare_2d_visualization( model, relations_set, figure_title, num_nodes=0, show_node_labels=['浦和レッズ'] + urawa ))
可視化の結果は次の通りです。チーム名が中心に来て、円周側に選手が配置されています。 gensimの実装では正則化の影響で周囲にノードが集結しすぎないような工夫がなされているため、ある程度の数のノードが中心付近に残っている模様です*7。
浦和レッズ所属経験のある選手にラベルを付与したところ、大半は右下に固まりました。興味深いのは、チーム名としての「浦和レッズ」の近くに「サンフレッチェ広島」が配置されている点です。森脇・柏木・槙野・西川・闘莉王など、サンフレッチェ広島から浦和レッズに移籍した選手の影響ではないかと推察しています。
次の図では、インタラクティブにデータを閲覧できます。
ちなみに、次のtwitterの投稿の際は学習が不十分だった模様です。
J1リーグの歴代の(選手, 所属チーム)を学習データにして、Poincaré Embeddingsで可視化してみた。チーム名が中心に来て、円周側に選手が配置されてる。浦和レッズ所属経験のある選手を目立たせてみたら、大半は右上に固まった一方で、右下に森脇・柏木・槙野・西川・闘莉王が配置されてて凄い。 pic.twitter.com/2wudm1BB7g
— u++ (@upura0) August 28, 2019
活用方法
個々のベクトルの値は、次のような形で参照できます。
model.kv['浦和レッズ']
array([ 0.64337554, -0.49962734])
得られたベクトルの活用方法としては、例えば一定の括りで少数派に当たるデータをまとめ上げる、類似するデータを検索するなどの方法が考えられます。Kaggleなど教師あり学習の文脈では、カテゴリ変数の粒度が粗い場合などに、活用の余地があり得るかなと思いました。
データサイエンティストが活躍する系の映画をオススメしてもらった
データサイエンティストが活躍する系の映画、なんか無いかな。Netflix漁ったら何かありそう。
— u++ (@upura0) August 26, 2019
私のtwitterでのしょうもない呟きに思いの外たくさんのリプライを頂戴したので、自分用の整理として推挙された映画をまとめます。広範な意味でのデータサイエンスを扱う映画も含まれていると思います。
既に観た映画
『マネーボール』『アルキメデスの大戦』『イミテーション・ゲーム/エニグマと天才数学者の秘密』を見て面白かったので、データサイエンス系は個人的ヒット率が高いと見ている🎥
— u++ (@upura0) August 26, 2019
次の3作品は、既に私が鑑賞済の映画です。
『イミテーション・ゲーム/エニグマと天才数学者の秘密』(2014)
第2次世界大戦時、ドイツの世界最強の暗号エニグマを解き明かした天才数学者アラン・チューリングの波乱の人生を描いた伝記ドラマ。劣勢だったイギリスの勝利に貢献し、その後コンピューターの概念を創造し「人工知能の父」と呼ばれた英雄にもかかわらず、戦後悲劇の運命をたどったチューリングを、ベネディクト・カンバーバッチが熱演する。
『アルキメデスの大戦』(2019)
1933年(昭和8年)、戦艦大和の建造をめぐる“机の上の大戦”が始まる。
これは、帝国海軍という巨大な権力に立ち向かい、数学で戦争を止めようとした男の物語。
映画『アルキメデスの大戦』予告【7月26日(金)公開】 - YouTube
ネタバレ要素を含みますが、以下に鑑賞録を記しています。
オススメしてもらった映画
『NUMBERS 天才数学者の事件ファイル』(2005)
犯罪者の行動を予測する公式を作る天才数学者の弟の協力で、さまざまな難しい犯罪を解明するFBIエージェントを描くドラマシリーズ。
『ミッション: 8ミニッツ』(2011)
列車爆破事故の犯人を見つけるべく、犠牲者が死亡する8分前の意識に入り込み、爆破直前の列車内を追体験していく男の運命を描く。困難なミッションを課せられた主人公を、『ブロークバック・マウンテン』のジェイク・ギレンホールが熱演。巧妙に練り上げられたプロットと先の読めないストーリー展開に引き込まれる。
「Sports Analyst Meetup #4」を開催&LTしました #spoana
はじめに
「Sports Analyst Meetup #4」を開催しました。前回に引き続き、自分自身もLTで発表しました。
ロングトーク①高久侑也さん(株式会社Sportip)
- Sportip*1のCEOを務める高久さんによるお話でした
- Sportipは、競技者の動きや姿勢など個人のデータを収集・分析できるような仕組みを提供しています
- デモも含めて、Sportipの取り組みやビジョンなどを語っていただきました
なお今回の会場は、Sportipが入居しているNTTドコモ・ベンチャーズ*2にご提供いただきました。ありがとうございました。
ロングトーク② TKB84さん
- 「スポーツ分析業界に飛び込んで半年で見えてきた、現状の概観と今後の展望」という題目での発表でした
- スポーツ分析業界で実際に働き始めたTKB84さんに、ご自身の経歴や現状の分析、そして「今後どのような人材が求められるか」という展望などの生々しい話も含めて語っていただきました。
LT
今回もどれも面白い12本のLTが実施されました。LTの内容については、発表資料やtogetterをご参照ください。
テーブルデータ向けのGAN(TGAN)で、titanicのデータを増やす
TGANとは
テーブルデータに対応した GAN (Generative Adversarial Network, 敵対的生成ネットワーク) *2 です。数値などの連続変数だけではなく、カテゴリ変数にも対応しています。
Titanic のデータを増やす
今回は、著名なデータセットである Titanic のデータを対象にTGANを試します。
データの読み込み
まずはデータを読み込みます。データは Kaggle からダウンロードしました*3。下図のようなデータが格納されています。
df = pd.read_csv('input/train.csv')
df.head()
行数は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)
'Age' が小数点以下になっているので丸める処理などは必要かもしれませんが、'Sex' などカテゴリ変数も含めてデータが生成できていると分かります。目的変数である 'Survived' も、問題なく増幅されていました。
samples['Survived'].value_counts()
0 540 1 310
おわりに
本記事では、TGAN を用いて titanic のデータを拡張してみました。Kaggle などの文脈で言うと、学習用データの水増しに利用できる可能性があります。ただし、ynktk さんとも議論した通り*6、GAN でまともなデータを作るにはそもそも十分量のデータセットが必要というジレンマがありそうです。
TGAN で増やしたデータで性能が向上するかはデータセットと課題設定次第ですが、機会があれば試してみても面白いなと思いました。
*1: テーブルデータ向けのGANらしい。どれくらい使えるんだろう。 https://t.co/zNQ0m3y5TA
*6: 論文読んでないから知らないけど、GANでそこそこまともなデータを生成できるくらい学習できるデータあるならデータ拡張あんまり効かないのでは?と思う。知らんけど
【ネタバレ有】『アルキメデスの大戦』とデータ分析の仕事
はじめに
OsciiArtさんの下記のツイートで興味を持ち、観に行きました。本記事では、ネタバレ要素を含みつつ、徒然と感想を書いていこうと思います。
『アルキメデスの大戦』を観た。傑作。kaggler、データサイエンティストは絶対に見て欲しい。kaggleのプロセスをそのままエンターテイメントに昇華している。こんなことが出来るなんて。感動だ。
— OsciiArt◆SPNEXTcRxQ (@osciiart) August 13, 2019
あらすじ
事前の触れ込み通り、まさに「データ分析」を題材にした映画で、主人公の天才数学者・櫂直が旧態依然の組織の中で奮闘します。
時は1933年、海軍では巨大戦艦の建造を巡った対立が発生していました。来たる戦争に向けて華美な巨大戦艦を建造したい「建造推進派」と、新世代の海戦を見据え機動力のある航空母艦を推す「建造反対派」です。
旧態依然な文化が根強く残る海軍の中では「建造推進派」が優勢でした。2週間後の最終決定の会議までに状況を覆したい山本五十六ら「建造反対派」は、巨大戦艦の建造費が過剰に小さく見積もられていると感じた点に目をつけました。
山本五十六は天才数学者の主人公に、巨大戦艦の建造費の正確な見積もりを依頼。しかし、主人公は戦艦のドメイン知識もなく、今回建造予定の巨大戦艦の詳細情報もありません。そのような中で付け焼き刃ながらドメイン知識を身につけ、地道な情報収集も重ねていきます。
「建造推進派」による数々の妨害にも屈せず、巨大戦艦の建造費の予測値を算出した主人公。予測値を突きつけられた「建造推進派」の反応、そして巨大戦艦の建造の顛末は・・・?
(続きは劇場で)
感想
『アルキメデスの大戦』、泣くタイプの映画じゃないのは百も承知だけど、いろいろ感情移入して泣いてしまった……
— u++ (@upura0) August 18, 2019
「データ分析の能力を見込まれた主人公」=「データサイエンティスト」と見立てて、感情移入してしまいました。まずは「データ分析で課題が解決できそう」という目論見で呼び出されるも、使えるデータがほとんどない状況。ドメイン知識もない主人公が自ら様々な場所に足を運んでデータを収集し、少しずつ知見を得ていく姿は胸を打つものがあります*1。
そして「建造推進派」による数々の妨害。主人公がデータを手に入れられないような政治的な根回しや、最終決定の会議の前倒しなど、フィクションでありながら妙なリアリティのある出来事*2が巻き起こります。「突然やってきた素人の主人公が成功したら困る」という理由で、「建造反対派」であるはずの設計士が主人公に非協力的な部分も、実に人間味にあふれて生々しかったです。
最後に、巨大戦艦の建造費の予測値を突きつける際の描写です。詳細部分は映画の根幹になってしまうので割愛しますが、如何に正しくても数式を押し付けるだけでは聴衆に響かない点や、数式を超越する物事の存在など、多くを考えさせられるクライマックスでした。
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 を試します。
利用するデータセット
今回は、sklearn に含まれている load_digits データセットを利用します*6。64次元の特徴量・0-9の10種類のラベルを持つ手書き数字のデータセットです。
画像は*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 データセットをそのまま可視化したところ、下図のようになりました。大まかに分かれてはいますが、中央付近など少し煩雑になっていると分かります。
可視化(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 実施前よりも、各クラスがハッキリと分かれているのが確認できます。
今回は全データで学習し、全データに適用しています。Metric Learning はデータ間の距離や類似度などの Metric を学習しているので、学習に用いていないデータセットに適用することが可能です。
例えば Kaggle のような教師あり機械学習の文脈で利用する場合には、train データセットで Metric を学習し、test データセットにも適用することになるでしょう。分離に適した新しい特徴量空間を用いることで、より分類性能が高いモデルの構築が期待されます。
おわりに
本記事では、scikit-learn-contrib の metric-learn パッケージに搭載されている Metric Learning を試しました。なかなか使い所が難しい印象もある技術ではありますが、選択肢の一つとして持っておく価値は多分にあると感じています。
*1:copypaste-ds.hatenablog.com
*3: metric learning is part of sklearn contribhttps://t.co/t8XUirRzBa