要素技術

[機械学習]機械学習の種類

はじめに

この記事は、(大分遅くなってしまい申し訳ありませんが)Machine Learning Advent Calendar 2016の記事です。
機械学習一般の話題。特にDeep Learning専用のカレンダーは既にあるので、Deep Learning以外の話題が望ましい。
Machine Learning Advent Calendar 2016 - Qiita - Qiita

やりたいこと

機械学習には入力データのあるなしや形式、出力データの形式などで複数のカテゴリがあります。教師あり・教師なし学習、回帰・分類といったカテゴリはどこでも見るのですが、例えば転移学習といった他の区分についての言及がある記事が少ない気がしています。 そこで、この記事では以下の3つの観点での機械学習の方法の分類(私の独断と偏見による分類です)を簡単に紹介したいと思います。ちなみに、MECEではなく正確でない記述もあると思います。
  • 出力データの形式に関する分類
  • 教師データの与え方に関する分類
  • 複数の学習機を用いた方法の分類
私自身、新しいものやかなりマイナーなものは全く追えてないのであくまで知っている範囲で紹介をしたいと思います。また、各アルゴリズムの詳細には踏み込みません。 以下のような人物をターゲットに記事を書きました。
  • scikit-learnを少し触ったことがある。
  • 回帰・分類・教師あり学習・教師なし学習の違いを分かっている。
  • 他にどんなタイプの機械学習があるか知りたい。

サマリだけ知りたい人用まとめ

  • 回帰:出力が連続値
  • 分類:出力が離散値
  • 構造予測:出力が構造を持ったオブジェクト
  • 教師あり学習:学習データは入力と答えのセット
  • 教師なし学習:学習データは入力のみ
  • 半教師あり学習:学習データは入力と答えのセットと入力のみの2種類
  • アンサンブル学習:複数の学習器の結果を組み合わせて最終的な答えを取得
  • 転移学習:以前に学習した学習器を別の問題に調整して使用
  • マルチタスク学習:複数の似た問題を解く複数の学習器を同時に学習

実行環境

基本的に、サンプルはpythonとscikit-learnを使ったものです。それぞれのバージョンは以下です。
  • python : 3.5.2
  • scikit-learn : 0.18.1
  • ipython : 5.1.0
私は、機械学習のアルゴリズムの確認は以下のDockerfileで作ったコンテナ上で行っています。
docker-config-mlenv - Dockerfile for machine learning environment(scikit-learn, chainer, gensim, tensorflow, jupyter)
zuqqhi2/docker-config-mlenv - GitHub

出力データの形式による分類

回帰・分類はおなじみの単語だと思いますが、この記事ではこの区分けの中に構造予測を入れています。というのも、構造予測は出力結果が構造を持つオブジェクトなので、出力結果が実数値の回帰と離散値の分類とは異なる区分になると考えているためです。 以下でそれぞれについて、具体例を簡単なコードを交えて簡単に紹介していきます。

回帰

回帰は答えが連続値(例えば1.414といった値で多次元値も含む)となるような問題です。以下のような問題が回帰の例です。
  • 住宅の相場価格予想
  • モーターの制御
この種の問題を機械学習で解く場合は、当然ですが、出力結果が連続値になるようなモデルを構築します(入力はなんでもいい)。

コード例

例としてUCI Machine Learning RepositoryのHousing Data Setを使って、住宅の価格予測をしてみます。 特徴量として使えるものはいくつかありますが、今回は簡単のためにRM(部屋の数)の1つのみ利用します。今回は線形回帰(単回帰)モデルというのを使って予測をやってみます。
#!/usr/bin/env python

import numpy as np
import pandas as pd
from sklearn.cross_validation import ShuffleSplit, train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score, make_scorer, mean_squared_error
from sklearn.grid_search import GridSearchCV

# Load UCI housing data set
data = pd.read_csv('./housing.data', delim_whitespace=True, header=None)
prices = data[[13]]
prices.columns = ['MEDV']
features = data[[5]]
features.columns = ['RM']

# Cross-Validation setting
X_train, X_test, y_train, y_test = train_test_split(features, prices, test_size=0.2, random_state=42)
cv_sets = ShuffleSplit(X_train.shape[0], n_iter = 10, test_size = 0.20, random_state = 0)
params = {'normalize': [False, True], 'fit_intercept': [False, True]}

# Learning
regressor = LinearRegression()
scoring_fnc = make_scorer(r2_score)
grid = GridSearchCV(regressor, params, cv=cv_sets, scoring=scoring_fnc)
best_reg = grid.fit(X_train, y_train)

# Prediction result
print("Prediction sample : room number = {0}, actual price = {1}, predicted price = {2}".format(X_test['RM'][0], y_test['MEDV'][0], best_reg.predict(X_test['RM'][0])[0][0]))
print("MSE : {}".format(mean_squared_error(y_test, best_reg.predict(X_test))))

# モデルの係数はインタプリタ上で以下を実行すれば確認できます。
# best_reg.best_estimator_.coef_
# best_reg.best_estimator_.intercept_
上記のコードを実行すると以下のようになります。
(実際に実行するといくつかDeprecationWarning警告が出ますが、推奨の方法の資料が見つからないので、あえてそのままにしてます。)
Prediction sample : room number = 6.575, actual price = 24.0, predicted price = 25.218762849584607
MSE : 46.144775347317264
得られたモデルを散布図上にプロットすると以下のようになります。

分類

分類は答えが離散値(連続ではない値。定義の仕方によるが、例えば1,2,3,4,..といったように小数点がないような値。多次元での表現もあり。)となるような問題です。以下のような問題が分類の例です。
  • 顔画像からの人物特定
  • 異常値判定
この種の問題を機械学習で解く場合は、当然ですが、出力結果が離散値になるようなモデルを構築します(入力はなんでもいい)。

コード例

例としてscikit-learnに入っているirisデータセットを使って、花弁とがくの幅と長さからirisの種類を判定します。 特徴量はすべて使い、決定木というモデルを使います。
#!/usr/bin/env python

import numpy as np
import pandas as pd
from sklearn.cross_validation import ShuffleSplit, train_test_split
from sklearn.tree import DecisionTreeClassifier, export_graphviz
from sklearn.metrics import f1_score, make_scorer, accuracy_score
from sklearn.grid_search import GridSearchCV
from sklearn import datasets
from pydotplus import graph_from_dot_data

# Load data
iris = datasets.load_iris()
features = iris.data
categories = iris.target

# Cross-Validation setting
X_train, X_test, y_train, y_test = train_test_split(features, categories, test_size=0.2, random_state=42)
cv_sets = ShuffleSplit(X_train.shape[0], n_iter = 10, test_size = 0.20, random_state = 0)
params = {'max_depth': np.arange(2,11), 'min_samples_leaf': np.array([5])}

# Learning
def performance_metric(y_true, y_predict):
  score = f1_score(y_true, y_predict, average='micro')
  return score

classifier = DecisionTreeClassifier()
scoring_fnc = make_scorer(performance_metric)
grid = GridSearchCV(classifier, params, cv=cv_sets, scoring=scoring_fnc)
best_clf = grid.fit(X_train, y_train)

# Prediction result
print("Optimal models's parameter 'max_depth' : {} ".format(best_clf.best_estimator_.get_params()['max_depth']))
print("Classifiction sample : features = {0}, actual category = {1}, classification result = {2}".format(X_test[0], y_test[0], best_clf.predict(np.array([X_test[0]])[0])[0]))
print("Accuracy : {}".format(accuracy_score(y_test, best_clf.predict(X_test))))

# Output decision tree
dot_data = export_graphviz(best_clf.best_estimator_, out_file=None,
                         feature_names=iris.feature_names,
                         class_names=iris.target_names,
                         filled=True, rounded=True,
                         special_characters=True)

graph = graph_from_dot_data(dot_data)
graph.write_pdf('iris_clf_tree.pdf')
このコードを実行した結果と最終的に得られた決定木は以下のようになりました。
Optimal models's parameter 'max_depth' : 3
Classifiction sample : features = [ 6.1  2.8  4.7  1.2], actual category = 1, classification result = 1
Accuracy : 1.0
“min_samples_leaf”をデフォルトのままにしていたら、以下のようにmax_depthが6となって過学習している感が出ました。なので、”min_samples_leaf”を5に設定しています。

構造予測

構造予測は答えが構造を持つオブジェクト(木やグラフなど)となるような問題です。以下のような問題が構造予測の例です。
  • 機械翻訳(2部グラフ)
  • 品詞推定(入力文書の各単語とその品詞の配列)
いわゆる系列ラベリング問題もここに含まれます。 この種の問題を機械学習で解く場合は、モデルの内部表現は問いませんが、出力結果が問題に合った構造を持つオブジェクトになる必要があります。

コード例

ここではHMM(隠れマルコフモデル)を用いて適当に作った系列ラベリング問題を解いてみます。 HMMにはhmmlearnというライブラリを使います。これはscikit-learnからHMMの部分を分離させたもので、将来的にscikit-learnからHMMが使えなくなるようです。

教師データの与え方に関する分類

教師あり学習

アクティブラーニング

オンライン学習

強化学習

教師なし学習

半教師あり学習

複数の学習機を用いた方法の分類

アンサンブル学習

バギング

ブートストラップ

転移学習(メタ学習?)

マルチタスク学習

おわりに

個人的には、アクティブラーニングや半教師あり学習は実践向きなのにネットや周りでは使ったという話を聞かないので不思議に思っています。
もちろん、データが十分にあれば使わなくても大丈夫ですが。
zuqqhi2

某Web系の会社でエンジニアをやっています。 学術的なことに非常に興味があります。 趣味は楽器演奏、ジョギング、読書、料理などなど手広くやっています。