はじめに
この記事を読むことで、scikit-learnの中身のコードに改変を加えることができるようになることを期待している。改変に必要な知識も学習できるようリンクを用意してある。そして改変を加えたコードをpipで管理する方法も示した。 最後には具体例として、決定木のfeature_importances_を可視化するメソッドをDecisionTreeClassifierに組み込む。
- はじめに
- scikit-learnのディレクトリ構造の俯瞰
- 開発環境を整える
- 編集した内容が反映されるようにインストールする
- 編集に必要な知識
- feature_importances_の可視化をscikit-learnに組み込む
- まとめ
- ソースコード等
本記事をおすすめしない人
- Pythonのリスト、タプル、辞書の違いは?と聞かれて答えられない方。
- 前半(6章まで)だけでいいのでPythonのチュートリアルをやりましょう。
- https://docs.python.org/ja/3/tutorial/
- 自分のPythonの環境をすぐに切り替えられない方
- まずは仮想環境の作り方やpyenvの使い方を覚えましょう
- 属性(attribute,メンバ)、メソッド、継承と言われてさっぱりな方
- Pythonのクラスについて勉強しましょう
- https://docs.python.org/ja/3/tutorial/classes.html
Pythonの基礎がわかっていればこの記事を読むのに苦労することは全くない。ただ、機械学習アルゴリズムに精通している方でもおすすめしない人に当てはまる方は苦労するかもしれない。
本記事をより良く理解するためには、実際に仮想環境(もしくはpyenvで環境ごと切り替え)を作り、実際にやってみることである。
既存のアルゴリズムに改変を加える研究をするぜ!と意気込む大学生の手助けになることを祈っている。
(オライリー本的な導入になってしまった。)
scikit-learnのディレクトリ構造の俯瞰
まずは、scikit-learnのディレクトリ構造を俯瞰してみよう。
githubのページはこちらだ。
./
には、README.md
をはじめとする書類系のファイルとsetup.py
をはじめとするinstallに必要なファイルがある。ディレクトリの方を見てみるとdoc/
やeaxmples/
などユーザーにとってありがたいファイルが入っているであろうディレクトリがある。
学習器が実際に記述されているのはsklearn/
の中だ。こちらの中を見ていこう。クリックするとこちらのページに飛ぶはずだ。
大枠としてのアルゴリズムの名称、もしくは処理の名称がディレクトリの名称としてつけられている。この一覧の中から自分が手を加えたいものをファイルを探して改変するわけである。
たとえばTreeの中を見てみよう。
中身はこういう構造になっている。
├── __init__.py ├── _criterion.pxd ├── _criterion.pyx ├── _reingold_tilford.py ├── _splitter.pxd ├── _splitter.pyx ├── _tree.pxd ├── _tree.pyx ├── _utils.pxd ├── _utils.pyx ├── export.py ├── setup.py ├── tests │ ├── __init__.py │ ├── test_export.py │ ├── test_reingold_tilford.py │ └── test_tree.py └── tree.py
すぐに_
から始まっているファイル名があるのに気がつくだろう。scikit-learnではユーザーが直接使わないファイルは_
から始まっている。この法則は一部のファイルに記載されている関数にも適応される。
(例えばforest.pyの冒頭で定義されている関数を見ればわかるだろう。この関数はユーザーが直接使うことを想定していない。)
また、.py以外の拡張子も存在することに気がつくだろう。.pyx
はCythonのファイルである。また.pxd
はCythonの補助ファイルである。Cythonについては後述する。
編集を始める前に、環境を整えて置こう。また編集したscikit-learnをimportしたときに編集が反映されるようにしておこう。
開発環境を整える
今の自分の環境が壊れないように、別の環境で作業をしよう。ここではpythonや環境の切り替えツールの導入方法は説明しない。各自使いこなせるものを持っていることを前提とする。
新しい環境にするとパッケージ(ライブラリ)が全然入っていないと思うが、インストールは読者に任せる(とはいえ、scikit-learnだけはインストールしないでほしい)
pyenvを用いた方法
筆者はpyenvを使用している。pyenvを用いているならば、仮想環境を用意するよりバージョンを切り替えたほうが手っ取り早いだろう。
pyenv install 3.6.2 #バージョンは3系の新しめなら何でも良い pyenv global 3.6.2 #さっきインストールしたバージョンに切り替え
筆者はAnaconda信者だが、あとでpipを用いることになるのでpyenv install
でAnacondaを用いることはおすすめしない。
venvを用いた方法
Python3ではvenvで仮想環境を構築することができる。pyenvを用いていないかたはこちらの方法で作成可能だろう。この方法でなくても慣れている方法で全然構わない。
python3 -m venv edit_sklearn #最後は好きな名称にしてください source edit_sklearn/bin/activate #ここも適切なものに変えてください
で切り替え可能。deactivate
で終了。
編集した内容が反映されるようにインストールする
さぁ、いよいよscikit-learnをインストールしよう。
環境の確認
まずは今の環境にscikit-learnが入っていないことを確認したい。
pip list | grep scikit
と打って scikit-learnと表示されなければ問題ない。すでにインストールされていた場合は、一旦アンインストールしよう。
pip uninstall scikit-learn
そして、いま、作業ディレクトリにいることを確認しよう。
pip install --editable
ここからは公式の手順で導入することにする。
まずはソースコードのダウンロードからだ。
#すこし時間がかかります。 git clone git://github.com/scikit-learn/scikit-learn.git
次にscikit-learnに必要な依存パッケージをインストールする。
pip install numpy scipy cython pytest pandas
そして、いよいよinstallする。
cd scikit-learn #さっきgit cloneしたディレクトリに移動 (手動でダウンロードすると名前がscikit-learn-masterになります) pip install --editable . #インストール!! #時間がかかります
install時にはcythonによるC, Cppへのコンパイル、さらにそれらから実行ファイルへのコンパイル等があるので時間がかかります。気長に待ちましょう。
トラブルシューティング
Cをコンパイルする工程でエラーが発生しinstallが終了する可能性がある。自分の計算機にgccがインストールされていてパスが問題ないか確認しよう。
Macを使っている人だと、コンパイラの関係でエラーが出てインストールに苦労するかもしれない。これはApple Clangが--openmp
という引数をサポートしていないのが原因だ。
brew install gcc #gccを導入
例えばbashをお使いならば、.bashrcに以下のようなエイリアスを書き込む。
# .bashrcに追記する export CC=gcc-8 #自分のgccのバージョンに合わせてください export CXX=gcc-8 export ARCHFLAGS="-arch x86_64" alias gcc=gcc-8 alias g++=g++-8
これでもだめなら、googleで検索するかstack overflowで質問をしよう。
準備完了
ここまで来たら、もう準備は完了である。'git clone'したscikit-learnをいじれば、いじった内容が即時で反映される。(jupyterを起動しているときはカーネルを一回シャットダウンする必要がある。)
Cythonファイルを編集した場合には、コンパイルの必要がある。再びscikit-learn/
の中で
pip install --editable .
を行えば良い。
もしくは、scikit-learn/
の中で
python setup.py build_ext --inplace
としてもokだ。筆者は後者派である。
好きなようにscikit-learnを改変しよう。研究に使うもよし、バグを修正してOSSに貢献するもよしだ。
編集に必要な知識
編集に必要な知識を身に着けるときに役立つサイトをまとめた。辞書代わりにどうぞ。
Pythonの知識
がんばろう
公式日本語ドキュメント
scikit-learn
引数の意味とかはソースコードよりもドキュメントのほうが早く探せる。
scikit-learn準拠モデル
自分で書いたモデルをscikit-learnとともに使うためにいくつかルールがある。scikit-learnに実装されているモデルももちろんそのルールにしたがっているので知っておくと良いだろう。なぜそれが継承されてる?という疑問も少なくなる。
Cythonの知識
実行時、速度のボトルネックになる部分はCythonを用いて実装されている。改変したい部分がCythonにある場合、知識が必要だろう。
公式ドキュメントの翻訳(アクセンステクノロジの増田さんすごい!)
Cython本 (Cythonの闇に飲み込まれたい方はおすすめです)
feature_importances_の可視化をscikit-learnに組み込む
具体例としてやっていく。
モデルは決定木、データはiris(楽なので)。
どういう可視化か
実際に組み込む前に、どういう風に可視化するのか追っていこう。まずはモデルを学習するところまで。
import numpy as np import pandas as pd import matplotlib.pyplot as plt %matplotlib inline %config InlineBackend.figure_formats = {'png', 'retina'} import seaborn as sns sns.set() #デザインのためだけのimport from sklearn.datasets import load_iris from sklearn import tree clf = tree.DecisionTreeClassifier(random_state=42) iris = load_iris() clf.fit(iris.data, iris.target)
DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None, max_features=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, presort=False, random_state=42, splitter='best')
はい、モデルの学習が終わった。 特徴量の重要度を見るには、
clf.feature_importances_
array([0.01333333, 0. , 0.56405596, 0.42261071])
とすればよいが、これをみてどの特徴量の重要度がどれぐらいと即座に分かる人は少ないだろう(特徴量の順番を覚えている超人は除く)。また特徴量の数が多くなったときは、表示が省略され見にくくなる。 そこで重要度を可視化して、見やすくしたい。
そのために以下のようなコードを書いた。
importance=pd.Series(data=clf.feature_importances_, index=iris.feature_names) importance=importance.sort_values() importance.plot.barh()
重要な特徴量から表示するような横向きの棒グラフである。これならば見やすい。
しかし、何回もこれ呼び出そうとすると面倒だ。そこでscikit-learnのDecisionTreeClassifierにメソッドとして組み込んでしまおうというわけである。
DecisionTreeClassifierの改変
DecisionTreeClassifierはこの場所で記述されている
897行目に以下のコードを挿入してあげよう。
def show_importances(self, feature_names, kwarg={}): """show feature importances in this model. Parameters ---------- fearure_names : list or array, shape = [n_features] feature names sequence when model trained. kwarg : keyword arguments of pandas plot """ import pandas as pd importance = pd.Series( data=self.feature_importances_, index=feature_names).sort_values() importance.plot.barh(**kwarg)
さて、もうすでにscikit-learnは改変された。ちゃんとpip install --editable .
でインストールしたscikit-learnであるば、.py
への編集は即時適応される。
今回は行わないが、もし.pyx
を編集したなら、python setup.py build_ext --inplace
を実行することも必要だ。
可視化、再訪
もう一度、特徴量重要度の可視化をやりなおしてみよう。まずは先程と同じく訓練終了まで実行する。
import numpy as np %matplotlib inline import seaborn as sns sns.set() #デザインのためだけのimport from sklearn.datasets import load_iris from sklearn import tree clf = tree.DecisionTreeClassifier(random_state=42) iris = load_iris() clf.fit(iris.data, iris.target)
可視化
clf.show_importances(iris.feature_names)
終わりである。 自作関数をクラスのメソッドとしてきれいにまとめる事ができた。
この具体例なら俺はもっと楽なやり方を知ってるぞ!という方もいると思う(実際ある)。しかし、既存のアルゴリズムを改変する、という作業はこの具体例で流れがつかめたことだろう。
まとめ
scikit-learnに改変を加えて使うため、必要な導入手順や知識の鱗片を紹介した。
また、最後には具体例として、feature_importances_
の可視化をメソッドとしてDecisionTreeClassifier
に追加した。
まとめようとすると、また長くなってしまいそうだ。読者がもう一回目次を読んで、どんなことを行ったかを思い出すことをまとめとしよう。
- はじめに
- scikit-learnのディレクトリ構造の俯瞰
- 開発環境を整える
- 編集した内容が反映されるようにインストールする
- 編集に必要な知識
- feature_importances_の可視化をscikit-learnに組み込む
- まとめ
- ソースコード等
ソースコード等
実験に用いたノートブック 出力が若干違いますが気にしないでください。
改変したtree.py
この部分にメソッドを追加したので、自分の環境のtree.pyにはりつければ使えるようになります。