自作したりネットから拾ってきたデータセットに、sklearnライクなインターフェースがあるとそこそこ便利です。
なので、作る方法について調べました。
とりあえずデータセットを読み込んで型を調べます。
>>> from sklearn.datasets import load_iris >>> iris = load_iris() >>> type(iris) <class 'sklearn.utils.Bunch'>
Bunchという型らしいです。
ではこのBunchを継承したクラスを定義してデータセットのオブジェクトを作るのかというとそうではなく、実はこのBunchというのは「キーにattribとしてアクセスできる辞書のようなもの」であり、コンストラクタに渡したキーと値のセットを内部で作ります。わかりづらいと思いますので例を示すと、
>>> from sklearn.datasets.base import Bunch >>> hoge = Bunch(hogehoge="hoge!") >>> hoge.hogehoge 'hoge!'
こうやって使えるということです。sklearnのソースを読んでも、このような形で使っているので間違いないようです。
https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/datasets/base.py
なので、自作のsklearnライクなデータセットを作りたいということであれば、このBunchをimportしてあげた上で、
Bunch(data=自作したnumpy配列のデータなど, target=自作したnumpy配列のターゲットなど)
こんな形で書けば良いということです。あとはload_***関数を作ってこのBunchのインスタンスをreturnしてやれば完了です。
ちなみに、Bunchのattribはその気になれば外部から上書きすることも可能。実際のdatasetsの実装もそうなっているようです。些か危ない気もしますが、pythonによくある「紳士協定で使え(間違った使い方なんかしないよね)」という奴でしょう。しかし、in-placeで処理される関数をうっかり呼び出したら普通に事故る気が・・・。
>>> from sklearn.datasets import load_iris >>> import numpy as np >>> iris = load_iris() >>> iris.data[:10] array([[5.1, 3.5, 1.4, 0.2], [4.9, 3. , 1.4, 0.2], [4.7, 3.2, 1.3, 0.2], [4.6, 3.1, 1.5, 0.2], [5. , 3.6, 1.4, 0.2], [5.4, 3.9, 1.7, 0.4], [4.6, 3.4, 1.4, 0.3], [5. , 3.4, 1.5, 0.2], [4.4, 2.9, 1.4, 0.2], [4.9, 3.1, 1.5, 0.1]]) >>> np.random.shuffle(iris.data) >>> iris.data[:10] array([[7.7, 2.8, 6.7, 2. ], [5.2, 3.5, 1.5, 0.2], [6.5, 3. , 5.8, 2.2], [5.1, 3.8, 1.5, 0.3], [6.2, 2.8, 4.8, 1.8], [4.4, 2.9, 1.4, 0.2], [4.9, 3. , 1.4, 0.2], [4.3, 3. , 1.1, 0.1], [6.4, 3.1, 5.5, 1.8], [6.8, 3.2, 5.9, 2.3]])
やはり事故るのだった。ちょっと怖いですねぇ。read-onlyにするのはそこまで難しくはないと思うのですが、敢えてそうしていないのか、単に実装がヘボいのか。
追記
公式リファレンス見たら、「Bunchオブジェクトは俺たちが便利に使うために用意しているだけだ、自分のデータセットで同じものを作ろうとはするな、Xとyを定義すりゃいいんだ」と言ってました。
Frequently Asked Questions — scikit-learn 0.22.2 documentation
自作データセットと組み込みのデータセットとでAPIを統一したいシチュエーションでは、ちょっと困りますね。でもまあ、やるなと言っているので、特殊な事情があるとき以外は自重しましょう。