PyCaretとは
PyCaret(Classification And REgression Training) は, scikit-learnや他の機械学習パッケージのラッパである. 色々な機械学習を自動的に行なってくれるので, 背景にある理論を理解していれば,容易に機械学習を行うことができる. 公式ページは https://pycaret.org/ である.
特徴としては,以下があげられる.
- 短いコードで機械学習ができる
- 自動化 (AutoML)
- オープンソース
ここでは,以下の5つを解説する.
- 回帰 (regression)
- 分類 (classification)
- クラスタリング (clustering)
- 異常検知(anomaly detection)
- アソシエーション・ルール・マイニング (association rule mining)
他にも,自然言語処理(natural language processing: NLP)や時系列 (time series) などが含まれている.
!pip install pycaret #すべてのパッケージをインストールするなら !pip install pycaret[full]
from pycaret.utils import enable_colab
enable_colab()
広告による売り上げの予測
広告のデータ http://logopt.com/data/Advertising.csv を用いる.
テレビ(TV),ラジオ(Radio),新聞(Newspaper)への広告から売り上げ(Sales)を予測する.
import pandas as pd
df = pd.read_csv(
"http://logopt.com/data/Advertising.csv", index_col=0
) # 0行目をインデックスにする.
df.tail()
独立変数(特徴ベクトル)$X$ は TV, Radio, Newspaperの列,従属変数(ターゲット) $y$ は Salesの列である.
PyCaretの基本手順
手順1: setup(データフレーム)で準備をする. 引数 target でターゲットの列を指定. 引数 session_id で乱数の種を指定する. 自動的にデータの型を判定して,入力待ちになる.大丈夫ならリターンを押す.すると,自動的に前処理が行われて,結果が表示される. 必要なら,前処理の方法を引数で指定し直す.
手順2: compare_modelsでモデルの比較を行う(もしくはcreate_modelでモデルを生成する). 引数 fold で交差検証用のデータの分割数を指定する. 返値は最良の評価値のモデルインスタンスである.
(注意: 遅い計算機で実行する際には,計算時間がかかるモデルを除いておくと良い.引数excludeで除きたいモデルのリストを入れる)
- 手順3: predict_modelで予測を行う.
from pycaret.regression import * # 回帰関連の関数のインポート
reg = setup(df, target="Sales", session_id=123)
best_model = compare_models(fold=5)
回帰モデル
No. | 略称 | 回帰モデル | 概要 |
---|---|---|---|
1 | et | Extra Trees Regressor | ランダムに分割してアンサンブルする決定木ベースの手法 |
2 | gbr | Gradient Boosting Regressor | 勾配ブースティング法 |
3 | xgboost | Extreme Gradient Boosting | xgブースト (勾配ブースティング法に正則化を追加) |
4 | rf | Random Forest Regressor | ランダム森(ブートストラップによるランダムサンプリングと決定木のアンサンブル) |
5 | catboost | CatBoost Regressor | カテゴリー変数の扱いに工夫を入れた勾配ブースティング法 |
6 | ada | AdaBoost Regressor | 適応型の勾配ブースティング法 |
7 | dt | Decision Tree Regressor | 決定木 |
8 | lightgbm | Light Gradient Boosting Machine | 勾配ブースティング法の軽量版 |
9 | knn | K Neighbors Regressor | $k$-近傍法 |
10 | lasso | Lasso Regression | Lasso回帰(正則化を入れた線形回帰) |
11 | en | Elastic Net | Elastic Net(正則化を入れた線形回帰) |
12 | lar | Least Angle Regression | 予測値と教師データの偏差と相関が大きい特徴量を1つずつ追加していく方法 |
13 | lr | Linear Regression | 線形回帰 |
14 | ridge | Ridge Regression | リッジ回帰(正則化を入れた線形回帰) |
15 | br | Bayesian Ridge | ベイズリッジ回帰 |
16 | huber | Huber Regressor | Huber回帰 |
17 | omp | Orthogonal Matching Pursuit | 貪欲に特徴量を1つずつ追加していく方法 |
18 | llar | Lasso Least Angle Regression | LassoにLeast Angle Regressionを適用して特徴量選択 |
19 | dummy | Dummy Regressor | ベースになる簡単なモデル |
20 | par | Passive Aggressive Regressor | オンライン型の学習 |
回帰モデルの評価尺度
以下の評価尺度が表示される. 定義については深層学習の章を参照されたい.
- MAE 平均絶対誤差 (mean absolute error)
- MSE 平均2乗誤差 (mean squared error)
- RMSE 平均2乗誤差の平方根 (root mean squared error)
- R2 決定係数(coefficient of determination) $R^2$
- RMSLE 平均2乗対数誤差の平方根 (root mean squared logarithmic error)
- MAPE 平均絶対パーセント誤差 (mean absolute percentage error)
- TT(sec) 計算時間
best_model
best_model_results = pull() # 結果をデータフレームとして得る.
best_model_results.to_csv("best_model.csv") #結果をcsvファイルに保存
predict_model(best_model)
可視化(回帰)
可視化の基本手順は以下の通り.
- 手順1: plot_model(モデルインスタンス)で描画する.引数plotで描画の種類を指定する.既定値は残差プロット.
- 手順2:interpret_model(モデルインスタンス)で,結果の解釈を可視化する.
plot_modelの引数plotの種類は以下の通り.
- "residuals": 残差プロット(既定値)
- "error" : 誤差プロット
- "cooks": Cookの距離プロット(外れ値をみる)
- "feature": 特徴重要度プロット
- "learning": 学習曲線
- "vc": 検証曲線
- "manifold": 次元削減を行い特徴を2次元に射影した図
- "parameter": モデルのパラメータを表で表示
- "tree": 決定木の図示(木ベースの場合のみ)
plot_model(best_model);
plot_model(best_model, plot="error");
plot_model(best_model, plot="cooks");
plot_model(best_model, plot="feature");
plot_model(best_model, plot="learning");
plot_model(best_model, plot="vc");
plot_model(best_model, plot="manifold");
plot_model(best_model, plot="parameter");
小さな(深さ3の)決定木 (dt) のモデルを作って可視化する.
dt = create_model("dt", max_depth=3)
plot_model(dt, plot="tree");
interpret_model(best_model);
interpret_model(best_model, plot="correlation");
interpret_model(best_model, plot="reason", observation=10)
問題 (SAT,GPA)
http://logopt.com/data/SATGPA.csv データを用いて,2種類のSATの成績からGPAを予測せよ.
データをそのまま使うと"MathSAT"列と"VerbalSAT"列をカテゴリー変数としてしまうので,浮動小数点数に変換しておく.
gpa = pd.read_csv(
"http://logopt.com/data/SATGPA.csv",
index_col=0,
dtype={"MathSAT": float, "VerbalSAT": float},
)
gpa.head()
問題(住宅価格)
http://logopt.com/data/Boston.csv のBostonの住宅データを用いて回帰分析を行え.
medvが住宅の価格で,他のデータ(犯罪率や人口など)から予測する.
問題(車の燃費)
http://logopt.com/data/Auto.csv の車の燃費のデータを用いて回帰分析を行え.
データの詳細については,
https://vincentarelbundock.github.io/Rdatasets/doc/ISLR/Auto.html
を参照せよ.
最初の列が燃費(mpg: Mile Per Gallon)であり,これを他の列の情報を用いて予測する.最後の列は車名なので無視して良い.
concrete = pd.read_csv("http://logopt.com/data/concrete.csv")
concrete.head()
bikeshare = pd.read_csv("http://logopt.com/data/bikeshare.csv")
bikeshare.head()
ダイアモンドの価格の予測(カテゴリー変数)
http://logopt.com/data/Diamond.csv からダイアモンドの価格データを読み込み,回帰による予測を行う.
列は ["carat","colour","clarity","certification","price"] であり,他の情報から価格(price)の予測を行え.
カラット(carat)以外の列は情報が文字列として保管されている.
これはカテゴリー変数とよばれる.
PyCaretでは,前処理関数setupで,自動的に変換してくれるので,手順は前とまったく同じである.
diamond = pd.read_csv("http://logopt.com/data/Diamond.csv", index_col=0)
diamond.head()
reg = setup(diamond, target="price", session_id=123)
best_model = compare_models(fold=5)
plot_model(best_model, plot="feature")
問題(車の価格)
http://logopt.com/data/carprice.csv から車の価格データを読み込み,回帰による予測を行え.
データの詳細は https://vincentarelbundock.github.io/Rdatasets/doc/DAAG/carprice.html にある.
車種(Type),100マイル走る際のガロン数(gpm100),都市部での1ガロンあたりの走行距離(MPGcity),高速道路での1ガロン当たりの走行距離(MPGhighway)から,価格(Price)を予測せよ.
import seaborn as sns
tips = sns.load_dataset("tips")
tips.head()
メールがスパム(spam;迷惑メイル)か否かを判定する例題を用いる.
https://archive.ics.uci.edu/ml/datasets/spambase
様々な数値情報から,is_spam列が $1$ (スパムでない)か, $0$ (スパム)かを判定する.
spam = pd.read_csv("http://logopt.com/data/spam.csv")
is_spam列が従属変数(ターゲット)$y$ になり,それ以外の列が独立変数(特徴ベクトル)$X$ になる.
from pycaret.classification import *
clf = setup(data=spam, target="is_spam", session_id=123)
best_model = compare_models()
分類モデル
No. | 略称 | 分類モデル | 概要 |
---|---|---|---|
1 | et | Extra Trees Classifier | ランダムに分割してアンサンブルする決定木ベースの手法 |
2 | gbc | Gradient Boosting Classifier | 勾配ブースティング法 |
3 | xgboost | Extreme Gradient Boosting | xgブースト (勾配ブースティング法に正則化を追加) |
4 | rf | Random Forest Classifier | ランダム森(ブートストラップによるランダムサンプリングと決定木のアンサンブル) |
5 | catboost | CatBoost Classifier | カテゴリー変数の扱いに工夫を入れた勾配ブースティング法 |
6 | ada | AdaBoost Classifier | 適応型の勾配ブースティング法 |
7 | dt | Decision Tree Classifier | 決定木 |
8 | lightgbm | Light Gradient Boosting Machine | 勾配ブースティング法の軽量版 |
9 | knn | K Neighbors Classifier | $k$-近傍法 |
10 | lda | Linear Discriminant Analysis | 線形判別分析(すべてのクラスで同じ正規分布を仮定) |
11 | qda | Quadratic Discriminant Analysis | 2次判別分析(各クラスで異なる正規分布を仮定) |
12 | lr | Logistic Regression | ロジスティック回帰 |
13 | ridge | Ridge Classifier | リッジ分類 |
14 | nb | Naive Bayes | 単純ベイズ |
15 | svm | SVM - Linear Kernel | サポートベクトルマシン(線形カーネル) |
16 | dummy | Dummy Classifier | ベースになる簡単なモデル |
分類モデルの評価尺度
以下の評価尺度が表示される. 解説のない評価尺度の定義については,機械学習ならびに深層学習の章を参照されたい.
- Accuracy:正解率
- AUC: area under the curve
- Recall: 再現率 (recall)
- Prec. : 適合率 (precision)
- F1 : f1 score
- Kappa
Cohenの提案した $\kappa$ (kappa) は,予測も正解もランダムに発生すると仮定したときの確率で補正した指標であり,以下のように定義される.
偶然TPになる確率(定義は2値分類の場合) $$p_{tp} = \frac{\mathrm{TP}+\mathrm{FN}}{\mathrm{TP}+\mathrm{FN}+\mathrm{FP}+\mathrm{TN}} \cdot \frac{\mathrm{TP}+\mathrm{FP}}{\mathrm{TP}+\mathrm{FN}+\mathrm{FP}+\mathrm{TN}}$$
偶然TNになる確率 $$p_{tn} = \frac{\mathrm{FN}+\mathrm{TN}}{\mathrm{TP}+\mathrm{FN}+\mathrm{FP}+\mathrm{TN}} \cdot \frac{\mathrm{FP}+\mathrm{TN}}{\mathrm{TP}+\mathrm{FN}+\mathrm{FP}+\mathrm{TN}}$$
偶然正解する確率 $$p_e = p_{tp} + p_{tn}$$
正解率 $$ p_0 = \frac{\mathrm{TP}+\mathrm{TN}}{\mathrm{TP}+\mathrm{FN}+\mathrm{FP}+\mathrm{TN}} $$
上の記号を用いると,$\kappa$は以下のようになる.
$$\kappa = \frac{p_0-p_e}{1-p_e}=\frac{2 \times (TP \times TN - FN \times FP)}{(TP + FP) \times (FP + TN) + (TP + FN) \times (FN + TN)}$$
- MCC (Matthews correlation coefficient)
MCCは,非均一データでも大丈夫で,かつ対称性をもつ(positiveとnegativeを入れ替えても同じ)という特徴をもつ指標であり,以下のように定義される.
$$\text{MCC} = \frac{ \mathrm{TP} \times \mathrm{TN} - \mathrm{FP} \times \mathrm{FN} } {\sqrt{ (\mathrm{TP} + \mathrm{FP}) ( \mathrm{TP} + \mathrm{FN} ) ( \mathrm{TN} + \mathrm{FP} ) ( \mathrm{TN} + \mathrm{FN} ) } }$$
- TT(Sec) 計算時間
可視化(分類)
可視化はplot_model(モデルインスタンス)で描画する.引数plotで描画の種類を指定できる. interpret_modelは回帰と同じである.
plot_model関数の引数plotの種類を以下に示す(回帰と同じものは省略).
- "auc": ROC曲線の下の面積 (既定値)
- "threshold": 識別閾値(discrimination threshold)を変えたときの評価尺度の変化
- "pr" : 適合率(precision)と再現率(recall)を表示
- "confusion_matrix": 混同行列
- "error": クラスごとの誤差を表示
- "class_report": クラスごとの評価尺度のヒートマップ
- "boundary": 決定の境界の図示
- "calibration": キャリブレーション(検量,較正)曲線の図示
- "dimension" : Dimension Learning
- "gain" : データの一部(パーセンテージ)でどれだけクラスを予測できたか(これをgainと呼ぶ)を表した図
- "lift" : 上のgainとベースライン(予測モデルを使わない場合)の比をプロットしたもの
plot_model(best_model, plot="auc");
plot_model(best_model, plot="threshold");
plot_model(best_model, plot="pr");
plot_model(best_model, plot="confusion_matrix");
plot_model(best_model, plot="error");
plot_model(best_model, plot="class_report");
plot_model(best_model, plot="boundary");
plot_model(best_model, plot="calibration");
plot_model(best_model, plot="dimension");
plot_model(best_model, plot="lift");
plot_model(best_model, plot="gain");
import plotly.express as px
iris = px.data.iris()
iris.head()
clf = setup(data=iris, target="species", ignore_features=["species_id"], session_id=123)
best_model = compare_models()
以下の可視化を行う.
- 混同行列 (ConfusionMatrix)
- 特徴重要度
3値以上の場合には,閾値を変化させる可視化はできないことに注意
plot_model(best_model, plot="confusion_matrix");
plot_model(best_model, plot="feature");
ここでは,データから毒キノコか否かを判定する使う.
target列がターゲット(従属変数)であり,edibleが食用,poisonousが毒である.
他の列のデータもすべて数値ではない.
PyCaretでは,自動的に前処理をしてくれるので,手順はまったく同じである.
mashroom = pd.read_csv("http://logopt.com/data/mashroom.csv")
mashroom.head()
from pycaret.classification import *
clf = setup(
data=mashroom,
target="target",
session_id=123,
log_experiment=True,
experiment_name="mashroom_1",
log_plots=True,
)
best_5 = compare_models(n_select=5)
tuned = [tune_model(i) for i in best_5]
bagged = [ensemble_model(i) for i in tuned]
blender = blend_models(estimator_list=tuned)
実験結果を表示
以下を実行して,ブラウザで http://127.0.0.1:5000 を開くと結果を対話的に確認できる.
!mlflow ui
credit = pd.read_csv("http://logopt.com/data/credit.csv")
credit.tail()
occupancy = pd.read_csv("http://logopt.com/data/occupancy.csv")
occupancy.tail()
titanic = pd.read_csv("http://logopt.com/data/titanic.csv")
titanic.head()
問題(胸部癌)
http://logopt.com/data/cancer.csv にある胸部癌か否かを判定するデータセットを用いて分類を行え.
最初の列diagnosisが癌か否かを表すものであり,"M"が悪性(malignant),"B"が良性(benign)を表す.
cancer = pd.read_csv("http://logopt.com/data/cancer.csv", index_col=0)
cancer.head()
クラスタリング
UCI機械学習レポジトリのワインに関するデータセットを用いてクラスタリングを解説する. 使用するのは $k$-平均法である.
元データは http://logopt.com/data/wine.data にある.
列名は https://archive.ics.uci.edu/ml/datasets/Wine で解説されている.
L = [
"Alcohol",
"Malic",
"Ash",
"Alcalinity",
"Magnesium",
"Phenols",
"Flavanoids",
"Nonflavanoid",
"Proanthocyanins",
"Color",
"Hue",
"OD280",
"OD315",
"Proline",
]
wine = pd.read_csv("http://logopt.com/data/wine.data", names=L)
wine.head()
from pycaret.clustering import *
cluster = setup(wine, session_id=123)
クラスタリングもcreate_model関数で生成する.引数modelでモデルの種類を設定する.
引数modelの種類は以下の通り (すべてscikit-learnを利用している).
- "kmeans": $k$-平均法(各点の重心までの距離の和を最小化)
- "ap": Affinity Propagation
- "meanshift": Mean shift Clustering
- "sc": スペクトラル・クラスタリング(低次元に射影してから$k$-平均法)
- "hclust": 階層的クラスタリング法
- "dbscan": DBSCAN (Density-Based Spatial Clustering)
- "optics": DBSCANの一般化
- "birch" : Birch Clustering
- "kmodes": $k$-Modes Clustering
クラスターの数は,引数num_clusters(既定値は4)で与える.
kmeans = create_model("kmeans", num_clusters=4)
得られたクラスタリングを元のデータフレームに書き込む.
kmean_results = assign_model(kmeans)
kmean_results.head()
クラスタリングの評価尺度
- Silhouette: シルエット値; クラスター内の平均距離 $a$ と最も近い別のクラスターとの平均距離 $b$ に対して $(b - a) / \max(a, b)$と定義される. 他のクラスターと離れているとき1に近くなる.
- Calinski-Harabasz: クラスター間の分散とクラスター内の分散の比を合計したもの;大きいほどクラスターが分離している.
- Davies-Bouldin:クラスター内と最も類似しているクラスター間の類似度の比の平均;小さいほどクラスターが分離している.
- Homogeneity: 均質性尺度;正解が必要; $0$ から $1$ の値をとり, $1$ に近いほど良い.
- Rand Index: 2つのクラスターに対して,正解と同じ割当になっている割合を表す尺度;$-1$から$1$の値をとり,$1$のとき正解と同じ.
- Completeness: 正解のクラスターに含まれるデータが,同じクラスターに含まれる割合;$0$から$1$の値をとり,$1$に近いほど良い.
ap = create_model("ap")
meanshift = create_model("meanshift")
sc = create_model("sc")
hclust = create_model("hclust")
dbscan = create_model("dbscan") # Bug?
optics = create_model("optics")
birch = create_model("birch")
kmodes = create_model("kmodes")
可視化(クラスタリング)
plot_model(モデルインスタンス)で可視化する.
plot_model関数の引数plotの種類は,以下の通り.
- "cluster": クラスターを主成分分析 (PCA) によって2次元に表示した図 (Plotly)
- "tsne": クラスターを$t$-SNE($t$-Distributed Stochastic Neighbor Embedding)によって3次元に表示した図(Plotly)
- "elbow": 分割数を表すパラメータ $k$ の適正化 (エルボー法)の図
- "silhouette" : シルエット係数 (クラスター内の平均距離 $a$ と最も近い別のクラスターとの平均距離 $b$ に対して $(b - a) / max(a, b)$ と定義される;他のクラスターと離れているとき1に近くなる)の図示
- "distance": クラスター間の距離の図示
- "distribution" : クラスターに含まれるデータ数の分布図(Plotly)
plot_model(kmeans, plot="cluster", save=True);
plot_model(kmeans, plot="tsne", save=True);
plot_model(kmeans, plot="elbow");
plot_model(kmeans, plot="silhouette");
plot_model(kmeans, plot="distance");
plot_model(kmeans, plot="distribution", save=True);
iris = px.data.iris()
iris.head()
df = get_data("mice")
print(df.shape)
from pycaret.anomaly import *
anomaly = setup(df, normalize = True, ignore_features=["MouseID"],session_id = 123)
モデルの生成
次に,モデルを生成する.モデル(アルゴリズム)の種類はmodel引数で指定する.ここでは,iforestを用いる.
モデルの種類は,以下の通り.
- "abod": Angle-base Outlier Detection.角度を用いることによって次元の呪いを回避した手法
- "cluster": Clustering-Based Local Outlier.クラスタリングを用いた手法
- "cof": Connectivity-Based Local Outlier.連結性を用いた手法
- "iforest": Isolation Forest.決定木を用いた手法
- "histogram": Histogram-based Outlier Detection.度数分布表(ヒストグラム)に基づく手法
- "knn": K-Nearest Neighbors Detector.$k$-近傍法
- "lof": Local Outlier Factor.局所的な外れ値尺度 (local outlier factor.$k$-近傍への平均距離の逆数)を用いた手法
- "svm": One-class SVM detector. サポートベクトルマシン
- "pca": Principal Component Analysis.主成分分析
- "mcd": Minimum Covariance Determinant.共分散行列の最小行列式に基づく手法
- "sod": Subspace Outlier Detection. 高次元データに対処するために部分空間を用いた手法
- "sos": Stochastic Outlier Selection.統計的外れ値検知法
iforest = create_model("iforest")
results = assign_model(iforest)
results.head().iloc[:,-10:] #最後の10列を表示
plot_model(iforest, save=True);
plot_model(iforest, plot = "umap", save=True);
spam = pd.read_csv("http://logopt.com/data/spam.csv")
spam.head()
df = get_data("france")
from pycaret.arules import *
rule = setup(data = df, transaction_id = "InvoiceNo", item_id = "Description", ignore_items=["POSTAGE"])
モデルの生成
create_modelで,アソシエーション・ルールを含んだデータフレームが生成される.
ルールは,「条件(antecedents) $\rightarrow$ 帰結(consequents)」の形式で表示され,評価尺度は以下の通りである.
事象 x の出現割合を support(x)と記す.
ルール「A -> C」に対して:
- antecedent support: support(A)
- consequent support: support(C)
- support: 支持度 support(A $+$ C)
- confidence: 信頼度 support(A $+$ C) $/$ support(A);既定値ではこの順に並んでいる.
- lift: リフト値 confidence(A $\rightarrow$ C) / support(C)
- leverage: support(A $\rightarrow$ C) $-$ support(A) $\times$ support(C)
- conviction: [1 $-$ support(C)] $/$ [1 $-$ confidence(A $\rightarrow$ C)]
model = create_model()
model.head()
plot_model(model); #save引数はない.
plot_model(model, plot="3d")
問題(アイルランドのオンラインショップ)
上の例題のデータは,オンラインショップのデータ https://archive.ics.uci.edu/ml/datasets/online+retail から,Country列が "France" のものを抽出したデータである. 以下のデータは,同じデータから Country列が "EIRE"(アイルランド)を抽出したものである. これを読み込み,上と同様のアソシエーション・ルール・マイニングを行え. ただし,今回はアイテム "POSTAGE" は除かなくて良い.
df = pd.read_csv("http://logopt.com/data/ireland.csv", index_col=0)
df.head()