創薬やマテリアルインフォはじめ、様々な分野に機械学習が浸透していますね。
機械学習の基礎を学ぼうとしたときや、自分の手法をテストしようとしたときに、良いデータセットを見つけるのに苦労したことはありませんか?
Sample Dataset Generatorはサンプルデータを自動生成するツールで、まさにそんな時に便利に使えるように自作しました。似たようなツールとして sklearn.datasets.make_regression や sklearn.datasets.make_classification などがありますが、それらより自由度が高く理解しやすいものを作ったつもりです。
以下のコードは https://github.com/maskot1977/sampledataset_generator.git で公開しており、 で動作確認済みです。
インストール
次のようにしてインストールできます。
!pip install git+https://github.com/maskot1977/sampledataset_generator.git
基本的な使い方
以下のような方法で、説明変数 X
と目的変数 Y
を自動的に作成できます。
from sampledataset_generator import generator
dataset = generator.SampleDatasetGenerator()
dataset.generate()
import pandas as pd
pd.DataFrame(dataset.X)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | -0.874719 | 0.228159 | 1.043060 | -0.064032 | 0.062203 | 2.938519 | -0.366674 | 1.087626 | 0.271206 | 1.396527 |
1 | -0.380454 | 0.070878 | 0.181825 | -0.172262 | 0.080013 | 0.420896 | 0.734195 | -0.340716 | -0.571168 | 1.437683 |
2 | -1.624316 | -0.312386 | -0.007409 | -0.001500 | -0.085444 | -0.117991 | -2.223847 | -0.318631 | 0.389458 | -0.217023 |
3 | -0.379374 | -0.058680 | -0.496479 | 0.541437 | 0.121997 | -0.468587 | -0.250380 | 0.038416 | 0.646550 | 0.869240 |
4 | 2.187036 | -0.014006 | 0.363903 | -0.509491 | 0.001101 | 1.084016 | 1.328812 | -1.241679 | 0.703932 | -0.157089 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
95 | -0.236994 | -0.159133 | 0.807234 | -0.083568 | 0.078701 | -0.105214 | -2.761139 | 0.043162 | -0.096247 | -0.106179 |
96 | -0.391223 | -0.014557 | 0.804878 | 0.040324 | 0.022574 | 0.717083 | -1.149362 | 1.051754 | -0.471551 | 0.333957 |
97 | 0.481387 | -0.038779 | 0.380662 | 0.857424 | 0.067420 | 1.599628 | -0.529226 | 0.071804 | -0.201889 | -0.087362 |
98 | 1.422031 | 0.021933 | -0.180896 | 0.644405 | -0.012918 | -1.929145 | -0.598751 | -1.371636 | 0.812930 | 0.000721 |
99 | -0.176868 | -0.003792 | 0.662571 | -0.799834 | -0.011456 | -2.083081 | -0.144673 | 0.154913 | 0.250457 | 0.331734 |
100 rows × 10 columns
pd.DataFrame(dataset.Y)
0 | |
---|---|
0 | 8.584018 |
1 | 1.502417 |
2 | -0.355069 |
3 | -2.698677 |
4 | 2.331078 |
... | ... |
95 | 6.929988 |
96 | 6.780913 |
97 | 4.847613 |
98 | -0.441276 |
99 | 4.126107 |
100 rows × 1 columns
デフォルトでは、X
から Y
を計算する式は多項式の一次式です。最初の5つの項のみが Y
を導出するために使用され、残りの項は Y
から独立しています。
pd.DataFrame(dataset.coef)
0 | |
---|---|
0 | 0.060915 |
1 | -0.548520 |
2 | 8.244854 |
3 | 1.599333 |
4 | 4.259971 |
5 | 0.000000 |
6 | 0.000000 |
7 | 0.000000 |
8 | 0.000000 |
9 | 0.000000 |
パラメーターと関数
デフォルトでは、n_samples
=100, n_features
=10, n_informative
=5, noise
=0.0, function
=linear
, independence
=1.0となっています。
-
n_samples
はサンプル数です。 -
n_features
は特徴量の数です。 -
n_informative
はデフォルトの多項式線形関数で Y を導出する際に用いられる「意味のある」特徴量 X の数です. -
noise
はノイズの強さを表します。 -
independence
は、Yの導出に用いられない「無関係な」特徴量が、「意味のある」特徴量からどれだけ独立しているかを表します。
非線形関数が必要な場合は、以下のような関数 friedman1
, friedman2
, friedman3
を用いることができます。
dataset = generator.SampleDatasetGenerator(function=generator.friedman1)
dataset.generate()
あるいは、任意の関数を定義して以下のように使用することもできます。
import numpy as np
my_func = lambda X, coef: np.arctan((X[:, 1] * X[:, 2] - 1 / (X[:, 1] * X[:, 3])) / X[:, 0])
dataset = generator.SampleDatasetGenerator(function=my_func)
dataset.generate()
欠損値を持つデータの作成
欠損値を含むデータは、以下の方法で作成することができます。欠損値の発生率を調整することができ、例えば rate
= 0.05 とすることができます。
dataset = generator.SampleDatasetGenerator()
dataset.generate()
dataset.fill_nan_randomly()
pd.DataFrame(dataset.X)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | NaN | -0.717267 | 0.466119 | 0.157829 | 0.403057 | 0.261670 | 1.621723 | -2.384312 | -0.419102 | -0.187467 |
1 | -0.226485 | 0.529230 | -1.417389 | -0.108385 | 0.108098 | 0.217466 | 1.137134 | 0.839975 | -0.329924 | NaN |
2 | -0.213283 | -0.980020 | NaN | -0.031286 | 0.252950 | -1.684535 | 1.525129 | -1.228553 | -0.815602 | NaN |
3 | -0.610736 | -0.601983 | 0.129403 | -0.041961 | -0.834912 | -0.447463 | 1.315553 | -0.935183 | NaN | -1.116784 |
4 | -0.550343 | -0.148456 | NaN | 0.757180 | 0.731174 | -0.562547 | 0.425136 | -0.848524 | -1.284881 | -0.720632 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
95 | -0.400990 | 0.010573 | -0.017612 | 0.323151 | 0.257867 | 0.008553 | -0.781648 | 0.031025 | -1.071831 | 1.435444 |
96 | -0.008266 | -0.945571 | -1.367276 | 0.396686 | 0.434881 | -0.684910 | -0.845351 | -0.597488 | -1.066122 | 0.822694 |
97 | 0.154777 | NaN | NaN | 0.259955 | 0.008274 | -0.866544 | -1.278649 | -0.711525 | -0.105661 | 1.192752 |
98 | 0.174639 | 0.208390 | 2.833820 | 0.352648 | -0.131895 | 1.685485 | 1.342137 | -0.594071 | 0.882873 | -1.190221 |
99 | 0.784510 | 0.443287 | -0.836974 | 0.000743 | 0.439658 | -2.741350 | 0.887365 | -0.530844 | 0.677080 | -0.525392 |
100 rows × 10 columns
疎なデータの作成
以下のようにゼロ値を持つデータを作成することができます。 例えば、rate
=0.9 のように、ゼロ値の出現率を調整することができます。
dataset = generator.SampleDatasetGenerator()
dataset.generate()
dataset.fill_zero_randomly()
pd.DataFrame(dataset.X)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.000000 |
1 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.000000 |
2 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.000000 |
3 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.000000 |
4 | 0.0 | 0.0 | 1.290429 | 0.0 | 0.000000 | 0.000000 | -0.620650 | 0.0 | 0.0 | 0.000000 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
95 | 0.0 | 0.0 | 0.000000 | 0.0 | 2.746314 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.000000 |
96 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.000000 | 0.254578 | 0.000000 | 0.0 | 0.0 | 1.269509 |
97 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.000000 |
98 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.000000 |
99 | 0.0 | 0.0 | 1.480686 | 0.0 | 0.000000 | 0.000000 | 0.673103 | 0.0 | 0.0 | 0.000000 |
100 rows × 10 columns
分類問題の目的変数
デフォルトでは、目的変数は連続であり、回帰問題を解くことを想定していますが、以下のようにすることで、目的変数を離散値として分類問題として扱うことができます。
dataset = generator.SampleDatasetGenerator()
dataset.generate()
dataset.categoricalize()
pd.DataFrame(dataset.Y)
0 | |
---|---|
0 | 1 |
1 | 1 |
2 | 0 |
3 | 1 |
4 | 0 |
... | ... |
95 | 0 |
96 | 0 |
97 | 0 |
98 | 0 |
99 | 0 |
100 rows × 1 columns
以下のようにすることで、任意のバイアスを持つ任意の数のカテゴリデータを生成できます。
dataset = generator.SampleDatasetGenerator()
dataset.generate()
dataset.categoricalize(
labels=["beer", "wine", "whiskey"],
classification_ratio=0.4
)
pd.DataFrame(dataset.Y)
0 | |
---|---|
0 | whiskey |
1 | whiskey |
2 | whiskey |
3 | whiskey |
4 | whiskey |
... | ... |
95 | whiskey |
96 | whiskey |
97 | beer |
98 | wine |
99 | whiskey |
100 rows × 1 columns
説明変数に離散値を含める
以下のようにすることで、与えられた列の説明変数をカテゴリ変数にできます。
dataset = generator.SampleDatasetGenerator()
dataset.generate()
dataset.categoricalize(column=3)
pd.DataFrame(dataset.X)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | -0.069141 | -0.152245 | -0.069177 | 1.0 | 2.147144 | 1.683370 | -1.406095 | -0.288278 | 0.021179 | 0.386266 |
1 | -0.017672 | -0.330113 | -0.233835 | 1.0 | -1.383669 | 0.352960 | 0.937982 | -1.835730 | 1.179513 | -0.555153 |
2 | -0.049318 | 0.672656 | -0.694506 | 1.0 | -0.250240 | 1.386238 | 1.016130 | 0.435432 | -0.102031 | -1.021133 |
3 | -0.035957 | -0.070815 | 0.086850 | 1.0 | -0.044765 | -0.424427 | 0.823290 | -2.021052 | -0.740976 | 0.774101 |
4 | 0.054945 | 0.316388 | -0.937645 | 0.0 | -1.004592 | -1.727037 | -0.325570 | -0.185780 | 0.660687 | -0.249081 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
95 | -0.050984 | 0.218996 | -0.436951 | 1.0 | 1.797569 | 1.522909 | 0.091088 | 1.819058 | 0.252704 | 1.506190 |
96 | -0.040341 | 0.239490 | -0.118325 | 1.0 | -0.750467 | -0.524603 | 1.785338 | -0.590646 | -0.311082 | -0.588058 |
97 | 0.032199 | 0.652054 | -0.293499 | 1.0 | -0.526053 | 0.753688 | 1.558890 | -1.672383 | 0.610953 | -0.076587 |
98 | -0.077576 | 0.222219 | -0.018319 | 0.0 | -0.393507 | -0.626555 | -0.160973 | -0.469242 | -0.435700 | -1.651206 |
99 | 0.001802 | 0.383190 | -0.018126 | 0.0 | -1.859617 | -0.601221 | 0.211747 | -0.244071 | -0.559714 | -1.454075 |
100 rows × 10 columns
以下のようにすることで、任意のバイアスを持つ任意の数のカテゴリデータを生成できます。
dataset.categoricalize(
column=5,
labels=["pen", "pineapple", "apple"],
classification_ratio=0.4
)
pd.DataFrame(dataset.X)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | -0.0691405 | -0.152245 | -0.0691765 | 1 | 2.14714 | pineapple | -1.4061 | -0.288278 | 0.0211786 | 0.386266 |
1 | -0.0176721 | -0.330113 | -0.233835 | 1 | -1.38367 | pen | 0.937982 | -1.83573 | 1.17951 | -0.555153 |
2 | -0.0493178 | 0.672656 | -0.694506 | 1 | -0.25024 | pineapple | 1.01613 | 0.435432 | -0.102031 | -1.02113 |
3 | -0.0359565 | -0.0708147 | 0.0868503 | 1 | -0.0447651 | apple | 0.82329 | -2.02105 | -0.740976 | 0.774101 |
4 | 0.0549453 | 0.316388 | -0.937645 | 0 | -1.00459 | apple | -0.32557 | -0.18578 | 0.660687 | -0.249081 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
95 | -0.0509837 | 0.218996 | -0.436951 | 1 | 1.79757 | pineapple | 0.0910875 | 1.81906 | 0.252704 | 1.50619 |
96 | -0.0403408 | 0.23949 | -0.118325 | 1 | -0.750467 | apple | 1.78534 | -0.590646 | -0.311082 | -0.588058 |
97 | 0.0321993 | 0.652054 | -0.293499 | 1 | -0.526053 | pineapple | 1.55889 | -1.67238 | 0.610953 | -0.0765871 |
98 | -0.0775761 | 0.222219 | -0.0183187 | 0 | -0.393507 | apple | -0.160973 | -0.469242 | -0.4357 | -1.65121 |
99 | 0.0018016 | 0.38319 | -0.0181257 | 0 | -1.85962 | apple | 0.211747 | -0.244071 | -0.559714 | -1.45408 |
100 rows × 10 columns
整数や非負数にしたい場合は以下のようにします。
dataset.categoricalize(
column=7,
labels=range(10),
classification_ratio=0.4
)
pd.DataFrame(dataset.X)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | -0.0691405 | -0.152245 | -0.0691765 | 1 | 2.14714 | pineapple | -1.4061 | 0 | 0.0211786 | 0.386266 |
1 | -0.0176721 | -0.330113 | -0.233835 | 1 | -1.38367 | pen | 0.937982 | 5 | 1.17951 | -0.555153 |
2 | -0.0493178 | 0.672656 | -0.694506 | 1 | -0.25024 | pineapple | 1.01613 | 6 | -0.102031 | -1.02113 |
3 | -0.0359565 | -0.0708147 | 0.0868503 | 1 | -0.0447651 | apple | 0.82329 | 5 | -0.740976 | 0.774101 |
4 | 0.0549453 | 0.316388 | -0.937645 | 0 | -1.00459 | apple | -0.32557 | 2 | 0.660687 | -0.249081 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
95 | -0.0509837 | 0.218996 | -0.436951 | 1 | 1.79757 | pineapple | 0.0910875 | 6 | 0.252704 | 1.50619 |
96 | -0.0403408 | 0.23949 | -0.118325 | 1 | -0.750467 | apple | 1.78534 | 0 | -0.311082 | -0.588058 |
97 | 0.0321993 | 0.652054 | -0.293499 | 1 | -0.526053 | pineapple | 1.55889 | 5 | 0.610953 | -0.0765871 |
98 | -0.0775761 | 0.222219 | -0.0183187 | 0 | -0.393507 | apple | -0.160973 | 0 | -0.4357 | -1.65121 |
99 | 0.0018016 | 0.38319 | -0.0181257 | 0 | -1.85962 | apple | 0.211747 | 2 | -0.559714 | -1.45408 |
100 rows × 10 columns
実験
以下のコードは https://github.com/maskot1977/sampledataset_generator.git で公開しており、 で動作確認済みです。
ここからは、データセットの種類や性質を変えることが予測精度にどのように影響するかを確認するために、いくつかの代表的な機械学習手法を実験します。 Sample Dataset Generator リポジトリでは、以下の実験用スクリプトを提供しています。
from sampledataset_generator import experiment
以下に、代表的な回帰手法の結果を載せますので、回帰手法の性質と、データセットの性質を考えながら、何が起こっているのか考えてみましょう!
線形重回帰 Linear Regression
independence
、noise
、n_features
を変更した場合の影響を見てみましょう。
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
experiment.benchmark(
"LinearRegression",
make_pipeline(
StandardScaler(),
LinearRegression()
)
)
線形関数
非線形関数
偏最小二乗回帰 Partial Least Square (PLS) Regression
independence
、noise
、n_features
を変更した場合の影響を見てみましょう。
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.cross_decomposition import PLSRegression
experiment.benchmark(
"PLSRegression",
make_pipeline(
StandardScaler(),
PLSRegression(n_components=10)
)
)
線形関数
非線形関数
サポートベクトル回帰 Support Vector Regression (SVR)
independence
、noise
、n_features
を変更した場合の影響を見てみましょう。
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVR
experiment.benchmark(
"SVR",
make_pipeline(
StandardScaler(),
SVR(C=50, gamma='auto', epsilon=1e-05)
)
)
線形関数
非線形関数
ランダムフォレスト回帰 Random Forest Regression
independence
、noise
、n_features
を変更した場合の影響を見てみましょう。
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestRegressor
experiment.benchmark(
"RandomForestRegressor",
make_pipeline(
StandardScaler(),
RandomForestRegressor(
random_state=1,
max_depth=8,
n_estimators=16
)
)
)
線形関数
非線形関数
多層パーセプトロン回帰 Multi-Layer Perceptron (MLP) Regression
independence
、noise
、n_features
を変更した場合の影響を見てみましょう。
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.neural_network import MLPRegressor
experiment.benchmark(
"MLPRegressor",
make_pipeline(
StandardScaler(),
MLPRegressor(
random_state=1,
max_iter=2000,
early_stopping=True,
hidden_layer_sizes=(
100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100
)
)
)
)
線形関数
非線形関数