第3回:機械学習概論:考え方と枠組み

3.1 機械学習イントロダクション

機械学習とは

学習 (learning)

大辞林より

  1. まなびおさめること.勉強すること.「新しい教科を―する」
  2. 〔生〕 生後の反復した経験によって,個々の個体の行動に環境に対して適応した変化が現れる過程.ヒトでは社会的生活に関与するほとんどすべての行動がこれによって習得される.
  3. 〔心〕 過去の経験によって行動の仕方がある程度永続的に変容すること.新しい習慣が形成されること.
  4. 〔教〕 新しい知識の獲得,感情の深化,よき習慣の形成などの目標に向かって努力を伴って展開される意識的行動.
3_gakushu.png
図1: ヒトの学習

機械学習 (machine learning)

プログラミングと機械学習

従来,機械(コンピュータ)に仕事をさせるには,人間が情報処理の手順や法則をプログラムとして記述し,機械に与えて実行していた

3_programming.png
図2: プログラミングによる情報処理

一方,機械学習による情報処理では,機械(コンピュータ)がデータから法則を自動的・統計的に学習する

3_machine_learning.png
図3: 機械学習による情報処理

機械学習の種類

教師あり学習 (supervised learning)

データにおける入力X(特徴量)と出力y(正解データ)関係f (y = f(X))を学習する. 機械学習の最も代表的なアプローチ.回帰分類の2タイプに大別される.

教師なし学習 (unsupervised learning)

正解データを指定せず,データそのものがどのような性質を持っているかを学習する. 代表的な方法に次元削減クラスタリングがある.

その他

機械学習を使うべきか使わざるべきか?

目的・問いを明確化する

機械学習向いている問題

機械学習が抱えるチャレンジ

機械学習とPython

3.2 機械学習の体験1(教師あり学習・分類)

アヤメ(Iris)の分類問題

ヒオウギ・アヤメ(Iris-Setosa)ブルーフラッグ (Iris-Versicolour)バージニカ (Iris-Virginica)
iris_setosa.jpgiris_versicolour.jpgiris_verginica.jpg
(C) Malcolm Manners - CC BY 2.0(C) Maja Dumat - CC BY 2.0(C) Frank Mayfield - CC BY-SA 2.0
図3:分類するアヤメの品種

Google Colabでやってみよう

Google Colabの起動

データのロード

データを眺める

#Pandasにも機能がある.ただし,色分けするのに手間なので,Seabornを使おう
pd.plotting.scatter_matrix(iris_data)

アヤメ問題の定式化

3_formulation.png
図4: アヤメ問題への機械学習の適用

機械学習を実行し,モデルを構築する

#特徴に使う列名リスト
features = ["がくの長さ", "がくの幅", "花びらの長さ", "花びらの幅"]
#正解データに使う列名
target = ["品種"]

X = data[features]
y = data[target]

from sklearn import tree
#決定木による分類モデルの構築
model = tree.DecisionTreeClassifier(random_state = 0, max_depth=3)
model.fit(X,y)

未知のデータで予測してみる

#未知のデータで予測してみる
new_data = pd.DataFrame([[4.8, 3.3, 1.4, 0.2],[7.3, 3.2, 4.4, 1.3],[5.5, 2.6, 5.5, 2.7] ], columns=features)
new_data
#予測してみる
model.predict(new_data)

アプリに組み込んでみる

#ユーザから入力を受け付けて,答えを出すプログラム
print("■アヤメの品種予測アプリ")
while True:
  input_str = input("がくの長さ・幅,花びらの長さ・幅を入力(0で終了):")
  if (len(input_str) == "0"):
    break
  vals = np.array(input_str.split()).astype(float)
  if (len(vals) != 4):
    print(" ×エラー:4つの数値が必要です.やり直し")
    continue
  df_params = pd.DataFrame([vals], columns=features)
  print(f" ○AI:品種は{model.predict(df_params)[0]}と思われます")
print("終了します")

何が起きたのか?

モデルを見てみる

3_decision_tree_iris.png
図5: 決定木によるアヤメの分類モデル

決定木アルゴリズムの直感的な解説

  1. はじめは全体グループを表す根ノードから始める
  2. 特徴量に関する条件を探し,それを満たすデータと満たさないデータに分割して,2つの子ノードを作る
    • この時,子ノードの不純度 (gini)がなるべく低くなるような条件を探索する
  3. 不純度が0になる,あるいは,指定された深さまで到達すれば終了.そうでなければ,2.に戻る
3_bunkatsu.png
図6: 決定木によって分割されたデータ

アルゴリズム詳細

疑問

モデルの評価 が必要

モデルを評価する

データを分割する:ホールドアウト法

3_train_test_split.png
図7: 訓練データとテストデータの分割
#X, yのそれぞれを訓練データとテストデータに分ける (訓練:テスト=2:1)
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=0)

#それぞれ確認してみる
print(X_train, X_test, y_train, y_test)

モデルの学習

モデルの評価

3_confusion_matrix.png
図8: 混同行列

モデルを保存する

モデルのセーブ

import pickle
with open("フォルダのパス名/保存ファイル名", "wb") as f
  pickle.dump(model, f)

モデルのロード

import pickle
with open("フォルダのパス名/保存ファイル名", "rb") as f
  model = pickle.load(f)
#以降,アプリでmodelを利用する

アヤメの分類問題・プログラム全体

  1. 必要なライブラリのインポート
    ###################  ライブラリのインポート #########################
    #いつものPandasとNumPyをインポート
    import pandas as pd
    import numpy as np
    
    #日本語化MatplotLib
    import matplotlib.pyplot as plt
    !pip install japanize-matplotlib
    import japanize_matplotlib
    
    # Seabornをインポート
    import seaborn as sns
    
    # Pickleをインポート
    import pickle
    
  2. データの取得
    ########################### データの取得 ############################
    #アヤメデータの取得
    iris_data = pd.read_csv("https://www2.cmds.kobe-u.ac.jp/~masa-n/dshandson/iris-sample.csv")
    
  3. データの理解・可視化
    ここでは省略.様々な角度から,データを眺めてみる(探索的データ分析:次回)
  4. 前処理
    ############################## 前処理 ################################
    
    #特徴量に指定する列名リスト
    features = ["がくの長さ", "がくの幅", "花びらの長さ", "花びらの幅"]
    
    # 正解データに指定する列名
    target = ["品種"]
    
    #特徴量
    X = iris_data[features] 
    
    #正解データ
    y = iris_data[target]
    
    #X, yのそれぞれを訓練データとテストデータに分ける (訓練:テスト=2:1)
    from sklearn.model_selection import train_test_split
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=0)
    
  5. モデルの選択と学習
    ###################### モデルの選択と学習 #############################
    
    #モデルの選択
    from sklearn import tree
    model = tree.DecisionTreeClassifier(max_depth=3, random_state=0)
    
    #モデルの学習(訓練データを使う)
    model.fit(X_train, y_train)
    
    #モデルの表示(オプショナル)
    tree.plot_tree(model, feature_names=X.columns)
    plt.show()
  6. モデルの評価
    ########################### モデルの評価 ###############################
    
    #分類精度
    acc = model.score(X_test, y_test)
    print(f"分類精度: {acc}")
    
    #実際にあっているかどうかを確認してみる (オプショナル)
    y_eval = pd.DataFrame()
    y_eval["正解"] = y_test["品種"]
    y_eval["予測"] = model.predict(X_test)
    y_eval["結果"] = (y_eval["正解"] == y_eval["予測"])
    print(y_eval)
    
    #混同行列を表示する (オプショナル)
    from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
    cm = confusion_matrix(y_test, model.predict(X_test))
    disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=model.classes_)
    disp.plot()
  7. モデルの保存
    with open("/content/drive/MyDrive/フォルダ名/ファイル名.pkl", "wb") as f:
       pickle.dump(model, f)

3.3 機械学習の体験2 (教師あり学習・回帰)

アヤメの花びらの回帰問題

Google Colabでやってみよう

準備~データの取得まで

前処理~モデルの学習まで

############################## 前処理 ################################

#特徴量に指定する列名リスト
features = ["品種", "がくの長さ", "がくの幅"]

# 正解データに指定する列名
target = ["花びらの長さ"]
 
#特徴量
X = iris_data[features] 

#正解データ
y = iris_data[target]

#X, yのそれぞれを訓練データとテストデータに分ける (訓練:テスト=2:1)
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=0)

###################### モデルの選択と学習 #############################
#モデルの選択(今回は線形回帰モデルを使用する)
from sklearn import linear_model
model = linear_model.LinearRegression()

#モデルの学習(訓練データを使う)
model.fit(X_train, y_train)

ダミー変数

3_dummy.png
図9:ダミー変数の説明
pd.get_dummies(data=iris_data, columns=["品種"], drop_first=True )
3_iris_dummy.png
図10:アヤメデータの品種をダミー変数化する

再び,前処理~モデルの学習まで

############################## 前処理 ################################

#ダミー変数化
iris_dummy = pd.get_dummies(data=iris_data, columns=["品種"], drop_first=True)

#特徴量に指定する列名リスト(ダミー変数化した後のデータから列名を選ぶ)
features = ["品種_Iris-versicolor", "品種_Iris-virginica", "がくの長さ", "がくの幅"]

# 正解データに指定する列名
target = ["花びらの長さ"]
  
#特徴量
X = iris_dummy[features] 
 
#正解データ
y = iris_dummy[target]
 
#X, yのそれぞれを訓練データとテストデータに分ける (訓練:テスト=2:1)
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=0) 

###################### モデルの選択と学習 #############################
#モデルの選択(今回は線形回帰モデルを使用する)
from sklearn import linear_model
model = linear_model.LinearRegression()

#モデルの学習(訓練データを使う)
model.fit(X_train, y_train)

モデルの評価

########################### モデルの評価 ###############################

#回帰の決定係数
r2 = model.score(X_test, y_test)
print(f"【決定係数】 {r2}")

#実際にあっているかどうかを確認してみる (オプショナル)
y_eval = pd.DataFrame()
y_eval["正解"] = y_test[target]
y_eval["予測"] = model.predict(X_test)
#数値の予測なので,正解と予測値の差(誤差)でモデルの良しあしを評価する
#引き算した結果1つ1つに絶対値absを適用している
y_eval["誤差"] = (y_eval["正解"] - y_eval["予測"]).apply(abs)
print(y_eval)
print(f"【平均絶対誤差(MAE)】{y_eval['誤差'].mean()}") 

#予測値と正解値を散布図にプロットしてみる
y_eval.plot.scatter(x="予測", y="正解")
#plt.show()

#同じことを行うライブラリがある
from sklearn.metrics import PredictionErrorDisplay, mean_absolute_error
disp = PredictionErrorDisplay(y_true = y_eval["正解"], y_pred= y_eval["予測"])
#実際値 vs 予測値 散布図
disp.plot(kind="actual_vs_predicted")
#残差 vs 予測 散布図
disp.plot()
#MAEを求める
mae = mean_absolute_error(y_true = y_eval['正解'], y_pred= y_eval['予測'])
print(f"【平均絶対誤差(MAE)】{mae}")

線形回帰アルゴリズムの直感的な解説

線形回帰モデルは,与えられた X=(x1,x2,...,xn) と y から,

y^ = w0 + w1 * x1 + w2 * x2 + ... + wn * xn

かつ,y^とyがなるべく近くなるような,w0,w1,...,wnを見つける.ここで wiは,

と呼ばれる.今回のモデルのそれぞれの値を求めると,

print(f"【切片】{model.intercept_}")
print(f"【偏回帰係数】{model.coef_}")
print(f"【特徴量名】{model.feature_names_in_}")

データフレームに入れて見やすくする

m_exp = pd.DataFrame()
m_exp.index = ["切片"] + model.feature_names_in_.tolist()
m_exp["重み"] = [model.intercept_[0]] + model.coef_[0].tolist()
m_exp
3_coef.png
図11: 花びら長さの線形回帰モデルの係数

すなわち,花びらの長さを以下の式で説明しようとしている

花びらの長さ (cm) = -1.531962
                   + 2.018762 * 品種_Iris_versicolor
                   + 2.916333 * 品種_Iris-virginica
                   + 0.699632 * がくの長さ
                   - 0.140591 * がくの幅

wiの求め方には最小二乗法が良く知られている.

アプリに組み込む

ユーザから品種とがくの長さ,幅を受け取って,花びらの長さを推定するアプリケーションを作ってみよう.

# アヤメの花びらの長さを推定する単純なアプリケーション

print("■アヤメの花びらの長さ推定アプリ Ver0.1")

while True:
  #品種の入力
  input_str = input("○品種を入力(0:ヒオウギ, 1:ブルーフラッグ, 2:バージニカ, 9:終了 )")
  #ダミー変数への割り当て
  if (input_str=="0"):
    (versicolor, virginica) = (0,0)
  elif (input_str=="1"):
    (versicolor, virginica) = (1,0)
  elif (input_str=="2"):
    (versicolor, virginica) = (0,1)
  elif (input_str=="9"):
    break
  else:
    print("番号が不正です.やり直し")
    continue

  input_str2 = input("○がくの長さと幅を入力:")
  #データを取得し,小数型へ
  params = np.array(input_str2.split()).astype(float)
  #個数が足りない場合はやり直し
  if len(params) != 2 :
    print("2つのデータがありません.やり直し")
    continue
  #データをデータフレームに入れて,予測する
  df_tmp = pd.DataFrame([[versicolor, virginica, params[0], params[1]]], columns=X.columns)
  pred = model.predict(df_tmp)
  #結果を表示
  print(f"このアヤメの花びらの長さは,推定{pred[0]}cm です.")

print("終了しました")

3.4 抑えておくべきポイント

教師あり機械学習の流れ

[添付]
図12: 教師あり機械学習モデルの開発プロセス

機械学習のチャレンジ

他の教師あり機械学習アルゴリズム

分類

回帰


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS