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

公開: 2022-03-11

この読書の主な目的は、Pythonのscikit-learnライブラリの機械学習アルゴリズムを活用できる十分な統計手法を理解し、この知識を適用して古典的な機械学習の問題を解決することです。

私たちの旅の最初のストップは、機械学習の簡単な歴史を通して私たちを連れて行きます。 次に、さまざまなアルゴリズムについて詳しく説明します。 最後に、タイタニックの生存率予測問題を解決するために学んだことを使用します。

いくつかの免責事項:

  • 私はフルスタックのソフトウェアエンジニアであり、機械学習アルゴリズムの専門家ではありません。
  • 基本的なPythonを知っていると思います。
  • これは探索的なものであるため、チュートリアルのようにすべての詳細が説明されているわけではありません。

それを踏まえて、飛び込みましょう!

機械学習アルゴリズムの簡単な紹介

この分野に足を踏み入れるとすぐに、機械学習は思ったほどロマンチックではないことに気づきます。 当初、私はもっと学んだ後、自分のジャービスAIを構築できるようになり、ソフトウェアのコーディングとお金の稼ぎに一日を費やして、屋外で本を読んだり、バイクを運転したりできるようになることを望んでいました。私の個人的なジャービスが私のポケットをより深くしている間、無謀なライフスタイルを楽しんでいます。 しかし、機械学習アルゴリズムの基盤は統計であることにすぐに気付きました。統計は、個人的には鈍くて面白くないと感じています。 幸いなことに、「鈍い」統計には非常に魅力的なアプリケーションがいくつかあることがわかりました。

これらの魅力的なアプリケーションにアクセスするには、統計を十分に理解する必要があることがすぐにわかります。 機械学習アルゴリズムの目標の1つは、提供されたデータの統計的依存関係を見つけることです。

提供されるデータは、年齢に対する血圧のチェックから、さまざまなピクセルの色に基づいた手書きのテキストの検索まで、何でもかまいません。

とはいえ、機械学習アルゴリズムを使用して暗号化ハッシュ関数(SHA、MD5など)の依存関係を見つけることができるかどうかを知りたいと思いましたが、適切な暗号プリミティブがそのように構築されているため、実際にはそれを行うことはできません。それらは依存関係を排除し、非常に予測が難しい出力を生成します。 無限の時間が与えられると、機械学習アルゴリズムはあらゆる暗号モデルをクラックする可能性があると私は信じています。

残念ながら、私たちはそれほど多くの時間を持っていないので、暗号通貨を効率的にマイニングする別の方法を見つける必要があります。 今までどこまで起きたの?

機械学習アルゴリズムの簡単な歴史

機械学習アルゴリズムのルーツは、18世紀に生きた英国の統計家であったトーマスベイズに由来します。 彼の論文「偶然論の問題の解決に向けたエッセイ」は、統計学の分野で広く適用されているベイズの定理を支えています。

19世紀に、ピエールシモンラプラスはベイズの定理を拡張し、今日私たちがベイズの定理として知っていることを定義して、 Theorie analytiquedesprobabilitesを発表しました。 その少し前に、Adrien-Marie Legendreは、教師あり学習で今日も広く使用されている「最小二乗」法について説明していました。

20世紀は、この分野で公に知られている発見の大部分が行われた時期です。 アンドレイ・マルコフは、詩を分析するために使用したマルコフ連鎖を発明しました。 Alan Turingは、人工知能になり、基本的に遺伝的アルゴリズムを予見できる学習マシンを提案しました。 フランク・ローゼンブラットはパーセプトロンを発明し、メディアで大きな興奮と大きな報道を引き起こしました。

しかし、1970年代には、AIのアイデアに多くの悲観論が見られ、その結果、資金が削減されたため、この期間はAIの冬と呼ばれます。 1980年代にバックプロパゲーションが再発見されたことで、機械学習の研究が復活しました。 そして今日、それは再びホットな話題です。

故レオ・ブレイマンは、データモデリングとアルゴリズムモデリングという2つの統計モデリングパラダイムを区別しました。 「アルゴリズムモデリング」とは、多かれ少なかれランダムフォレストのような機械学習アルゴリズムを意味します。

機械学習と統計は密接に関連する分野です。 Michael I. Jordanによると、方法論の原理から理論的なツールまで、機械学習のアイデアは統計学において長い先史時代を持っていました。 彼はまた、機械学習の専門家と統計家の両方が暗黙のうちに取り組んでいる全体的な問題のプレースホルダー用語としてデータサイエンスを提案しました。

機械学習アルゴリズムのカテゴリ

機械学習の分野は、教師あり学習教師なし学習という2つの主要な柱に基づいています。 一部の人々はまた、新しい研究分野である深層学習を、教師あり学習と教師なし学習の問題とは別のものと見なしています。

教師あり学習とは、コンピューターに入力とその望ましい出力の例が提示される場合です。 コンピューターの目的は、入力を出力にマップする一般式を学習することです。 これはさらに次のように分類できます。

  • 半教師あり学習。これは、コンピューターに不完全なトレーニングセットが与えられ、一部の出力が欠落している場合です。
  • アクティブラーニング。これは、コンピューターが非常に限られたインスタンスのセットのトレーニングラベルしか取得できない場合です。 インタラクティブに使用すると、トレーニングセットをユーザーに提示してラベルを付けることができます。
  • 強化学習。これは、トレーニングデータが、車両の運転や対戦相手とのゲームのプレイなど、動的な環境でのプログラムのアクションへのフィードバックとしてのみ提供される場合です。

対照的に、教師なし学習は、ラベルがまったく与えられていない場合であり、入力内の構造を見つけるのはアルゴリズム次第です。 教師なし学習は、隠れたパターンを発見するだけでよい場合、それ自体が目標になる可能性があります。

ディープラーニングは、人間の脳の構造と機能に触発され、単なる統計的概念ではなく人工ニューラルネットワークに基づく新しい研究分野です。 ディープラーニングは、教師ありアプローチと教師なしアプローチの両方で使用できます。

この記事では、より単純な教師あり機械学習アルゴリズムの一部のみを確認し、それらを使用して、タイタニック号の悲劇的な沈没における個人の生存率を計算します。 ただし、一般的に、使用するアルゴリズムがわからない場合は、scikit-learnの機械学習アルゴリズムのチートシートから始めるとよいでしょう。

基本的な教師あり機械学習モデル

おそらく最も簡単なアルゴリズムは線形回帰です。 これは直線としてグラフィカルに表現できる場合もありますが、その名前にもかかわらず、多項式の仮説がある場合は、代わりにこの線を曲線にすることができます。 いずれにせよ、スカラー従属変数$y$と$x$で示される1つ以上の説明値の間の関係をモデル化します。

素人の言葉で言えば、これは線形回帰が既知の各$x$と$y$の間の依存関係を学習するアルゴリズムであり、後でそれを使用して$x$の未知のサンプルの$y$を予測できることを意味します。

最初の教師あり学習の例では、基本的な線形回帰モデルを使用して、年齢を考慮して人の血圧を予測します。 これは、年齢と血圧という2つの意味のある機能を備えた非常に単純なデータセットです。

すでに上で述べたように、ほとんどの機械学習アルゴリズムは、提供されたデータの統計的依存関係を見つけることによって機能します。 この依存関係は仮説と呼ばれ、通常は$ h(\ theta)$で表されます。

仮説を理解するために、データをロードして調査することから始めましょう。

 import matplotlib.pyplot as plt from pandas import read_csv import os # Load data data_path = os.path.join(os.getcwd(), "data/blood-pressure.txt") dataset = read_csv(data_path, delim_whitespace=True) # We have 30 entries in our dataset and four features. The first feature is the ID of the entry. # The second feature is always 1. The third feature is the age and the last feature is the blood pressure. # We will now drop the ID and One feature for now, as this is not important. dataset = dataset.drop(['ID', 'One'], axis=1) # And we will display this graph %matplotlib inline dataset.plot.scatter(x='Age', y='Pressure') # Now, we will assume that we already know the hypothesis and it looks like a straight line h = lambda x: 84 + 1.24 * x # Let's add this line on the chart now ages = range(18, 85) estimated = [] for i in ages: estimated.append(h(i)) plt.plot(ages, estimated, 'b')

[<matplotlib.lines.Line2D at 0x11424b828>]

年齢と血圧のグラフに示されている線形仮説。

上のグラフでは、すべての青い点がデータサンプルを表しており、青い線はアルゴリズムが学習する必要のある仮説です。 では、とにかくこの仮説は正確には何ですか?

この問題を解決するには、$x$と$y$の間の依存関係を学習する必要があります。これは、$ y = f(x)$で表されます。 したがって、$ f(x)$は理想的なターゲット関数です。 機械学習アルゴリズムは、未知の$ f(x)$の最も近い近似である仮説関数$ h(x)$を推測しようとします。

線形回帰問題の最も単純な仮説の形式は、次のようになります。$ h_ \ theta(x)= \ theta_0 + \ theta_1 *x$。 単一のスカラー変数$y$を出力する単一の入力スカラー変数$x$があります。ここで、$ \theta_0$と$\theta_1$は学習する必要のあるパラメーターです。 この青い線をデータに当てはめるプロセスは、線形回帰と呼ばれます。 入力パラメーター$x_1$が1つしかないことを理解することが重要です。 ただし、多くの仮説関数にはバイアス単位($ x_0 $)も含まれます。 したがって、結果として得られる仮説は、$ h_ \ theta(x)= \ theta_0 * x_0 + \ theta_1 *x_1$の形式になります。 ただし、ほとんどの場合1に等しいため、$x_0$の記述を避けることができます。

青い線に戻ります。 私たちの仮説は$h(x)= 84 + 1.24x $のように見えます。これは、$ \ theta_0 =84$および$\theta_1 =1.24$を意味します。 これらの$\theta $値を自動的に導出するにはどうすればよいですか?

コスト関数を定義する必要があります。 基本的に、コスト関数が行うことは、モデル予測と実際の出力の間の二乗平均平方根誤差を単純に計算することです。

\ [J(\ theta)= \ frac {1} {2m} \ sum_ {i = 1} ^ m(h_ \ theta(x ^ {(i)})-y ^ {(i)})^ 2 \ ]

たとえば、私たちの仮説では、48歳の人の場合、血圧は$ h(48)= 84 + 1.24 * 48 =143mmHg$である必要があります。 ただし、トレーニングサンプルでは、​​$ 130mmHg$の値があります。 したがって、エラーは$(143-130)^ 2 =169$です。 次に、トレーニングデータセットのすべてのエントリについてこのエラーを計算し、それを合計する必要があります($ \ sum_ {i = 1} ^ m(h_ \ theta(x ^ {(i)})-y ^ {(i )})^ 2 $)そしてその中から平均値を取ります。

これにより、関数のコストを表す単一のスカラー数が得られます。 私たちの目標は、コスト関数が最小になるような$ \theta$値を見つけることです。 つまり、コスト関数を最小化する必要があります。 これは直感的に見えることを願っています。コスト関数の値が小さい場合、これは予測の誤差も小さいことを意味します。

 import numpy as np # Let's calculate the cost for the hypothesis above h = lambda x, theta_0, theta_1: theta_0 + theta_1 * x def cost(X, y, t0, t1): m = len(X) # the number of the training samples c = np.power(np.subtract(h(X, t0, t1), y), 2) return (1 / (2 * m)) * sum(c) X = dataset.values[:, 0] y = dataset.values[:, 1] print('J(Theta) = %2.2f' % cost(X, y, 84, 1.24))

J(Theta) = 1901.95

ここで、コスト関数値が最小になるように、$ \theta$のそのような値を見つける必要があります。 しかし、どうすればそれを行うことができますか?

\ [minJ(\ theta)= \ frac {1} {2m} \ sum_ {i = 1} ^ m(h_ \ theta(x ^ {(i)})-y ^ {(i)})^ 2 \ ]

考えられるアルゴリズムはいくつかありますが、最も一般的なのは最急降下法です。 最急降下法の背後にある直感を理解するために、最初にそれをグラフにプロットしてみましょう。 簡単にするために、より単純な仮説$ h(\ theta)= \ theta_1 *x$を仮定します。 次に、単純な2Dチャートをプロットします。ここで、$x$は$\theta $の値であり、$y$はこの時点でのコスト関数です。

 import matplotlib.pyplot as plt fig = plt.figure() # Generate the data theta_1 = np.arange(-10, 14, 0.1) J_cost = [] for t1 in theta_1: J_cost += [ cost(X, y, 0, t1) ] plt.plot(theta_1, J_cost) plt.xlabel(r'$\theta_1$') plt.ylabel(r'$J(\theta)$') plt.show() 

凸コスト関数。

コスト関数は凸関数です。つまり、区間$ [a、b]$には最小値が1つだけあります。 これもまた、最良の$ \ theta $パラメータは、コスト関数が最小になるポイントにあることを意味します。

基本的に、最急降下法は、関数を最小化するパラメーターのセットを見つけようとするアルゴリズムです。 これは、パラメーターの初期セットから始まり、関数勾配の負の方向に繰り返しステップを実行します。

コスト関数の最小値を見つける。

特定の点で仮説関数の導関数を計算すると、その点での曲線の接線の傾きが得られます。 これは、グラフ上のすべてのポイントで勾配を計算できることを意味します。

アルゴリズムが機能する方法は次のとおりです。

  1. ランダムな開始点(ランダムな$ \ theta $)を選択します。
  2. この時点でコスト関数の導関数を計算します。
  3. 勾配$\theta_j:= \ theta_j-\ lambda * \ frac {\ partial} {\ partial \ theta_j} * J(\ theta)$に向かって小さな一歩を踏み出します。
  4. 収束するまで手順2〜3を繰り返します。

ここで、収束条件はアルゴリズムの実装に依存します。 50ステップ後、何らかのしきい値の後、またはその他の方法で停止する場合があります。

 import math # Example of the simple gradient descent algorithm taken from Wikipedia cur_x = 2.5 # The algorithm starts at point x gamma = 0.005 # Step size multiplier precision = 0.00001 previous_step_size = cur_x df = lambda x: 2 * x * math.cos(x) # Remember the learning curve and plot it while previous_step_size > precision: prev_x = cur_x cur_x += -gamma * df(prev_x) previous_step_size = abs(cur_x - prev_x) print("The local minimum occurs at %f" % cur_x)

The local minimum occurs at 4.712194

この記事では、これらのアルゴリズムを実装しません。 代わりに、広く採用されているオープンソースのPython機械学習ライブラリであるscikit-learnを利用します。 さまざまなデータマイニングや機械学習の問題に非常に役立つAPIを多数提供します。

 from sklearn.linear_model import LinearRegression # LinearRegression uses the gradient descent method # Our data X = dataset[['Age']] y = dataset[['Pressure']] regr = LinearRegression() regr.fit(X, y) # Plot outputs plt.xlabel('Age') plt.ylabel('Blood pressure') plt.scatter(X, y, color='black') plt.plot(X, regr.predict(X), color='blue') plt.show() plt.gcf().clear() 

血圧対年齢のグラフで学習した線形仮説

<matplotlib.figure.Figure at 0x120fae1d0>

 print( 'Predicted blood pressure at 25 yo = ', regr.predict(25) ) print( 'Predicted blood pressure at 45 yo = ', regr.predict(45) ) print( 'Predicted blood pressure at 27 yo = ', regr.predict(27) ) print( 'Predicted blood pressure at 34.5 yo = ', regr.predict(34.5) ) print( 'Predicted blood pressure at 78 yo = ', regr.predict(78) )
 Predicted blood pressure at 25 yo = [[ 122.98647692]] Predicted blood pressure at 45 yo = [[ 142.40388395]] Predicted blood pressure at 27 yo = [[ 124.92821763]] Predicted blood pressure at 34.5 yo = [[ 132.20974526]] Predicted blood pressure at 78 yo = [[ 174.44260555]]

統計データの種類

機械学習の問題でデータを操作するときは、さまざまな種類のデータを認識することが重要です。 数値(連続または離散)、カテゴリ、または順序データがある場合があります。

数値データは測定値としての意味があります。 たとえば、年齢、体重、人が所有するビットコインの数、または人が1か月に書くことができる記事の数などです。 数値データは、さらに離散型と連続型に分類できます。

  • 離散データは、アパートの部屋の数やコイントスの数など、整数で数えることができるデータを表します。
  • 連続データは必ずしも整数で表すことはできません。 たとえば、ジャンプできる距離を測定している場合、2メートル、1.5メートル、または1.652245メートルの場合があります。

カテゴリデータは、人の性別、結婚歴、国などの値を表します。このデータは数値をとることができますが、これらの数値には数学的な意味はありません。 それらを一緒に追加することはできません。

順序データは、数学的に意味のある方法でカテゴリに番号を付けることができるという点で、他の2つのタイプを組み合わせたものにすることができます。 一般的な例は評価です。多くの場合、1から10のスケールで評価するように求められ、整数のみが許可されます。 これを数値的に使用することはできますが(たとえば、何かの平均評価を見つけるために)、機械学習手法を適用する場合、データをカテゴリ別であるかのように扱うことがよくあります。

ロジスティック回帰

線形回帰は、数値を予測するのに役立つ優れたアルゴリズムです。たとえば、特定のサイズと部屋数の家の価格などです。 ただし、次のような質問への回答を得るために、カテゴリデータを予測したい場合もあります。

  • これは犬ですか、それとも猫ですか?
  • この腫瘍は悪性ですか、それとも良性ですか?
  • このワインは良いですか悪いですか?
  • このメールはスパムですか?

あるいは:

  • 写真に写っている番号はどれですか?
  • このメールはどのカテゴリに属しますか?

これらの質問はすべて、分類問題に固有のものです。 そして、最も単純な分類アルゴリズムはロジスティック回帰と呼ばれ、仮説が異なることを除いて、最終的には線形回帰と同じになります。

まず、同じ線形仮説$ h_ \ theta(x)= \ theta ^ TX $を再利用できます(これはベクトル化された形式です)。 線形回帰は区間$[a、b] $内の任意の数を出力できますが、ロジスティック回帰は$ [-1、1] $の値のみを出力できます。これは、オブジェクトが特定のカテゴリに分類されるかどうかの確率です。

シグモイド関数を使用して、任意の数値を変換して、区間$ [-1、1]$の値を表すことができます。

\ [f(x)= \ frac {1} {1 + e ^ x} \]

ここで、$ x $の代わりに、既存の仮説を渡す必要があるため、次のようになります。

\ [f(x)= \ frac {1} {1 + e ^ {\ theta_0 + \ theta_1 * x_1 + ... + \ theta_n * x_n}} \]

その後、仮説がゼロより大きい場合、これは真の値であり、そうでない場合は偽であるという単純なしきい値を適用できます。

\ [h_ \ theta(x)= \ begin {cases} 1&\ mbox {if} \ theta ^ TX> 0 \\ 0&\ mbox {else} \ end {cases} \]

これは、同じコスト関数と同じ勾配降下アルゴリズムを使用して、ロジスティック回帰の仮説を学習できることを意味します。

次の機械学習アルゴリズムの例では、スペースシャトルのパイロットに、自動または手動の着陸制御を使用するかどうかをアドバイスします。 6つの機能とグラウンドトゥルースで構成される非常に小さなデータセット(15サンプル)があります。

機械学習アルゴリズムでは、「グラウンドトゥルース」という用語は、教師あり学習手法に対するトレーニングセットの分類の精度を指します。

データセットは完全です。つまり、不足している機能はありません。 ただし、一部の機能にはカテゴリの代わりに「*」が付いています。これは、この機能が重要ではないことを意味します。 このようなアスタリスクはすべてゼロに置き換えます。

 from sklearn.linear_model import LogisticRegression # Data data_path = os.path.join(os.getcwd(), "data/shuttle-landing-control.csv") dataset = read_csv(data_path, header=None, names=['Auto', 'Stability', 'Error', 'Sign', 'Wind', 'Magnitude', 'Visibility'], na_values='*').fillna(0) # Prepare features X = dataset[['Stability', 'Error', 'Sign', 'Wind', 'Magnitude', 'Visibility']] y = dataset[['Auto']].values.reshape(1, -1)[0] model = LogisticRegression() model.fit(X, y) # For now, we're missing one important concept. We don't know how well our model # works, and because of that, we cannot really improve the performance of our hypothesis. # There are a lot of useful metrics, but for now, we will validate how well # our algorithm performs on the dataset it learned from. "Score of our model is %2.2f%%" % (model.score(X, y) * 100)

Score of our model is 73.33%

検証?

前の例では、学習データを使用してモデルのパフォーマンスを検証しました。 しかし、私たちのアルゴリズムがデータをアンダーフィットまたはオーバーフィットする可能性があることを考えると、これは今では良いオプションですか? 家のサイズを表す1つの機能と、その価格を表す別の機能がある場合の、より簡単な例を見てみましょう。

 from sklearn.pipeline import make_pipeline from sklearn.preprocessing import PolynomialFeatures from sklearn.linear_model import LinearRegression from sklearn.model_selection import cross_val_score # Ground truth function ground_truth = lambda X: np.cos(15 + np.pi * X) # Generate random observations around the ground truth function n_samples = 15 degrees = [1, 4, 30] X = np.linspace(-1, 1, n_samples) y = ground_truth(X) + np.random.randn(n_samples) * 0.1 plt.figure(figsize=(14, 5)) models = {} # Plot all machine learning algorithm models for idx, degree in enumerate(degrees): ax = plt.subplot(1, len(degrees), idx + 1) plt.setp(ax, xticks=(), yticks=()) # Define the model polynomial_features = PolynomialFeatures(degree=degree) model = make_pipeline(polynomial_features, LinearRegression()) models[degree] = model # Train the model model.fit(X[:, np.newaxis], y) # Evaluate the model using cross-validation scores = cross_val_score(model, X[:, np.newaxis], y) X_test = X plt.plot(X_test, model.predict(X_test[:, np.newaxis]), label="Model") plt.scatter(X, y, edgecolor='b', s=20, label="Observations") plt.xlabel("x") plt.ylabel("y") plt.ylim((-2, 2)) plt.title("Degree {}\nMSE = {:.2e}".format( degree, -scores.mean())) plt.show() 

過適合と過剰適合を示すために、1次、4次、および30次の多項式でモデル化された同じデータ。

機械学習アルゴリズムモデルは、トレーニングデータも新しい観測値も一般化できない場合、適切ではありません。 上記の例では、実際のトレーニングデータセットを実際には表していない単純な線形仮説を使用しており、パフォーマンスが非常に低くなります。 通常、アンダーフィッティングは、適切なメトリックがあれば簡単に検出できるため、説明されていません。

アルゴリズムが表示されたすべての観測値を記憶している場合、トレーニングデータセット外の新しい観測値ではパフォーマンスが低下します。 これは過剰適合と呼ばれます。 たとえば、30次多項式モデルはほとんどのポイントを通過し、トレーニングセットで非常に良いスコアを持ちますが、それ以外のものはパフォーマンスが低下します。

私たちのデータセットは1つの特徴で構成されており、2D空間で簡単にプロットできます。 ただし、実際には、数百の特徴を備えたデータセットが存在する可能性があるため、ユークリッド空間で視覚的にプロットすることは不可能です。 モデルが過適合か過適合かを確認するために、他にどのようなオプションがありますか?

学習曲線の概念を紹介する時が来ました。 これは、トレーニングサンプルの数に対する平均二乗誤差をプロットする単純なグラフです。

学習教材では、通常、次のようなグラフが表示されます。

多項式の次数に基づく理論的な学習曲線の変化。

ただし、実際には、このような完璧な画像が得られない場合があります。 各モデルの学習曲線をプロットしてみましょう。

 from sklearn.model_selection import learning_curve, ShuffleSplit # Plot learning curves plt.figure(figsize=(20, 5)) for idx, degree in enumerate(models): ax = plt.subplot(1, len(degrees), idx + 1) plt.title("Degree {}".format(degree)) plt.grid() plt.xlabel("Training examples") plt.ylabel("Score") train_sizes = np.linspace(.6, 1.0, 6) # Cross-validation with 100 iterations to get a smoother mean test and training # score curves, each time with 20% of the data randomly selected as a validation set. cv = ShuffleSplit(n_splits=100, test_size=0.2, random_state=0) model = models[degree] train_sizes, train_scores, test_scores = learning_curve( model, X[:, np.newaxis], y, cv=cv, train_sizes=train_sizes, n_jobs=4) train_scores_mean = np.mean(train_scores, axis=1) test_scores_mean = np.mean(test_scores, axis=1) plt.plot(train_sizes, train_scores_mean, 'o-', color="r", label="Training score") plt.plot(train_sizes, test_scores_mean, 'o-', color="g", label="Test score") plt.legend(loc = "best") plt.show() 

1次、4次、および30次の多項式でモデル化されたデータを使用した3つのグラフのトレーニングスコアとテストスコア。

シミュレートされたシナリオでは、トレーニングスコアを表す青い線は直線のように見えます。 実際には、それでもわずかに減少します。これは、実際には1次多項式グラフで確認できますが、他のグラフでは、この解像度で判断するには微妙すぎます。 少なくとも、「高バイアス」シナリオでのトレーニングとテスト観測の学習曲線の間に大きなギャップがあることがはっきりとわかります。

中央の「通常の」学習率グラフでは、トレーニングスコアとテストスコアの線がどのように組み合わされているかを確認できます。

また、「高分散」グラフでは、サンプル数が少ない場合、テストとトレーニングのスコアが非常に似ていることがわかります。 ただし、サンプル数を増やすと、トレーニングスコアはほぼ完全なままですが、テストスコアはそれから離れていきます。


非線形仮説、たとえば、より多くの多項式の特徴を持つ仮説を使用する場合、不適合モデル(高バイアスのモデルとも呼ばれます)を修正できます。

私たちの過剰適合モデル(高分散)は、示されているすべての例を通過します。 ただし、テストデータを導入すると、学習曲線間のギャップが広がります。 正則化、交差検定、およびその他のデータサンプルを使用して、過剰適合モデルを修正できます。

相互検証

過剰適合を回避するための一般的な方法の1つは、利用可能なデータの一部を保持し、それをテストセットとして使用することです。 ただし、多項式の特徴の数など、さまざまなモデル設定を評価する場合、パラメーターを微調整して最適な推定器のパフォーマンスを実現できるため、テストセットを過剰適合させるリスクがあります。そのため、テストセットに関する知識は次のようになります。モデルに漏れます。 この問題を解決するには、「検証セット」と呼ばれるデータセットのもう1つの部分を保持する必要があります。 トレーニングはトレーニングセットで進行し、最適なモデルパフォーマンスが達成されたと考えられる場合は、検証セットを使用して最終評価を行うことができます。

ただし、利用可能なデータを3つのセットに分割することで、モデルのトレーニングに使用できるサンプルの数を大幅に減らすことができ、結果は、トレーニングと検証のセットのペアの特定のランダムな選択に依存する可能性があります。

この問題の1つの解決策は、相互検証と呼ばれる手順です。 標準の$k$フォールド交差検定では、データをフォールドと呼ばれる$k$サブセットに分割します。 次に、残りのフォールドをテストセットとして使用しながら、$ k-1 $フォールドでアルゴリズムを繰り返しトレーニングします(「ホールドアウトフォールド」と呼ばれます)。

k分割交差検定におけるホールドアウトフォールドの位置を示すグリッド。

交差検定を使用すると、元のトレーニングセットのみを使用してパラメーターを調整できます。 これにより、最終モデルを選択するための真に目に見えないデータセットとしてテストセットを保持できます。

Pを除外する、層化された$ k $フォールドシャッフルと分割など、さらに多くの相互検証手法がありますが、これらはこの記事の範囲を超えています。

正則化

これは、モデルの過剰適合の問題を解決するのに役立つもう1つの手法です。 ほとんどのデータセットには、パターンとノイズがあります。 正則化の目的は、モデルに対するノイズの影響を減らすことです。

元の関数とその正則化された関数を並べたグラフ。

ラッソ、ティホノフ、エラスティックネットの3つの主要な正則化手法があります。

L1正則化(またはLasso正則化)は、ゼロに縮小するいくつかの機能を選択して、最終モデルでそれらが何の役割も果たさないようにします。 L1は、重要な機能を選択する方法と見なすことができます。

L2正則化(またはTikhonov正則化)は、すべての機能を比較的小さくし、モデルへの影響を少なくします。

エラスティックネットは、L1とL2の組み合わせです。

正規化(機能スケーリング)

特徴のスケーリングも、データを前処理する際の重要なステップです。 データセットには、値が$ [-\ infty、\ infty] $のフィーチャと、スケールが異なるその他のフィーチャが含まれている場合があります。 これは、独立した値の範囲を標準化する方法です。

機能のスケーリングも、学習モデルのパフォーマンスを向上させるための重要なプロセスです。 まず、すべての機能が同じ基準にスケーリングされている場合、最急降下法ははるかに速く収束します。 また、サポートベクターマシン(SVM)などの多くのアルゴリズムは2点間の距離を計算することで機能し、フィーチャの1つに広い値がある場合、距離はこのフィーチャの影響を大きく受けます。

ベクターマシンのサポート

SVMは、分類と回帰の問題に使用できる、さらに広く普及している機械学習アルゴリズムです。 SVMでは、各観測値を$ n $次元空間の点としてプロットします。ここで、$n$は私たちが持っている特徴の数です。 各フィーチャの値は、特定の座標の値です。 次に、2つのクラスを十分に分離する超平面を見つけようとします。

2つのクラスのデータポイントを分離する超平面を示すグラフ。サポートベクターの一部も示されています。

最適な超平面を特定した後、マージンを追加します。これにより、2つのクラスがさらに分離されます。

マージンのある超平面を示すグラフ。

SVMは、特徴の数が非常に多い場合、または特徴の数がデータサンプルの数よりも多い場合に非常に効果的です。 ただし、SVMはベクトルベースで動作するため、使用する前にデータを正規化することが重要です。

ニューラルネットワーク

ニューラルネットワークアルゴリズムは、おそらく機械学習研究の最もエキサイティングな分野です。 ニューラルネットワークは、脳のニューロンがどのように接続されているかを模倣しようとします。

ニューラルネットワークの図。一時的な値にマッピングされたさまざまな入力を示しています。一時的な値は、単一の出力にマッピングされています。

これがニューラルネットワークの外観です。 多くのノードを組み合わせて、各ノードが一連の入力を受け取り、それらにいくつかの計算を適用して、値を出力します。

教師あり学習と教師なし学習の両方に対応するニューラルネットワークアルゴリズムには、さまざまなものがあります。 ニューラルネットワークは、自動運転車の運転、ゲームのプレイ、飛行機の着陸、画像の分類などに使用できます。

悪名高いタイタニック

RMSタイタニック号は、氷山と衝突した後、1912年4月15日に北大西洋に沈んだ英国の客船でした。 約2,224人の乗組員と乗客がおり、1,500人以上が死亡し、これは史上最も致命的な商業海事災害の1つとなっています。

これで、分類問題に使用される最も基本的な機械学習アルゴリズムの背後にある直感を理解したので、タイタニック号に搭乗している人の生存結果を予測するために知識を適用できます。

私たちのデータセットは、Kaggleデータサイエンスコンテストプラットフォームから借用されます。

 import os from pandas import read_csv, concat # Load data data_path = os.path.join(os.getcwd(), "data/titanic.csv") dataset = read_csv(data_path, skipinitialspace=True) dataset.head(5)
PassengerId 生き残ったPclass 名前セックスSibSp パーチチケット運賃キャビン着手
0 1 0 3 ブラウン、オーウェン・ハリス氏22.0 1 0 A / 5 21171 7.2500 NaN S
1 2 1 1 カミングス、ジョン・ブラッドリー夫人(Florence Briggs Th .. .. 女性38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 ヘイキネン、ミス・ライナ女性26.0 0 0 STON/O2。 3101282 7.9250 NaN S
3 4 1 1 フットレル、ジャック・ヒース夫人(リリー・メイ・ピール) 女性35.0 1 0 113803 53.1000 C123 S
4 5 0 3 アレン、ウィリアム・ヘンリー氏35.0 0 0 373450 8.0500 NaN S

最初のステップは、データを読み込んで調査することです。 891件のテストレコードがあります。 各レコードの構造は次のとおりです。

  • passengerId –搭乗中の乗客のID
  • 生存–人が墜落を生き延びたかどうか
  • pclass –チケットクラス、例:1st、2nd、3rd
  • 性別–乗客の性別:男性または女性
  • 名前–タイトルが含まれています
  • 年齢–年齢(年)
  • sibsp –タイタニック号に搭乗している兄弟/配偶者の数
  • 羊皮紙–タイタニック号に乗っている親/子の数
  • チケット–チケット番号
  • 運賃–旅客運賃
  • キャビン–キャビン番号
  • 乗船–乗船港

このデータセットには、数値データとカテゴリデータの両方が含まれています。 通常、データをさらに深く掘り下げ、それに基づいて仮定を立てることをお勧めします。 ただし、この場合、このステップをスキップして、予測に直接進みます。

 import pandas as pd # We need to drop some insignificant features and map the others. # Ticket number and fare should not contribute much to the performance of our models. # Name feature has titles (eg, Mr., Miss, Doctor) included. # Gender is definitely important. # Port of embarkation may contribute some value. # Using port of embarkation may sound counter-intuitive; however, there may # be a higher survival rate for passengers who boarded in the same port. dataset['Title'] = dataset.Name.str.extract(' ([A-Za-z]+)\.', expand=False) dataset = dataset.drop(['PassengerId', 'Ticket', 'Cabin', 'Name'], axis=1) pd.crosstab(dataset['Title'], dataset['Sex'])
Title \ Sex 女性
Capt 0 1
コル0 2
伯爵夫人1 0
ドン0 1
博士1 6
Jonkheer 0 1
レディ1 0
選考科目0 2
マスター0 40
逃す182 0
Mlle 2 0
Mme 1 0
0 517
夫人125 0
MS 1 0
Rev 0 6
お客様0 1
 # We will replace many titles with a more common name, English equivalent, # or reclassification dataset['Title'] = dataset['Title'].replace(['Lady', 'Countess','Capt', 'Col',\ 'Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Other') dataset['Title'] = dataset['Title'].replace('Mlle', 'Miss') dataset['Title'] = dataset['Title'].replace('Ms', 'Miss') dataset['Title'] = dataset['Title'].replace('Mme', 'Mrs') dataset[['Title', 'Survived']].groupby(['Title'], as_index=False).mean()
タイトル生き残った
0 マスター0.575000
1 逃す0.702703
20.156673
3 夫人0.793651
4 他の0.347826
 # Now we will map alphanumerical categories to numbers title_mapping = { 'Mr': 1, 'Miss': 2, 'Mrs': 3, 'Master': 4, 'Other': 5 } gender_mapping = { 'female': 1, 'male': 0 } port_mapping = { 'S': 0, 'C': 1, 'Q': 2 } # Map title dataset['Title'] = dataset['Title'].map(title_mapping).astype(int) # Map gender dataset['Sex'] = dataset['Sex'].map(gender_mapping).astype(int) # Map port freq_port = dataset.Embarked.dropna().mode()[0] dataset['Embarked'] = dataset['Embarked'].fillna(freq_port) dataset['Embarked'] = dataset['Embarked'].map(port_mapping).astype(int) # Fix missing age values dataset['Age'] = dataset['Age'].fillna(dataset['Age'].dropna().median()) dataset.head()
生き残ったPclass セックスSibSp Parch 運賃着手タイトル
0 0 3 0 22.0 1 0 7.2500 0 1
1 1 1 1 38.0 1 0 71.2833 1 3
2 1 3 1 26.0 0 0 7.9250 0 2
3 1 1 1 35.0 1 0 53.1000 0 3
4 0 3 0 35.0 0 0 8.0500 0 1

At this point, we will rank different types of machine learning algorithms in Python by using scikit-learn to create a set of different models. It will then be easy to see which one performs the best.

  • Logistic regression with varying numbers of polynomials
  • Support vector machine with a linear kernel
  • Support vector machine with a polynomial kernel
  • 神経網

For every single model, we will use $k$-fold validation.

 from sklearn.model_selection import KFold, train_test_split from sklearn.pipeline import make_pipeline from sklearn.preprocessing import PolynomialFeatures, StandardScaler from sklearn.neural_network import MLPClassifier from sklearn.svm import SVC # Prepare the data X = dataset.drop(['Survived'], axis = 1).values y = dataset[['Survived']].values X = StandardScaler().fit_transform(X) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state = None) # Prepare cross-validation (cv) cv = KFold(n_splits = 5, random_state = None) # Performance p_score = lambda model, score: print('Performance of the %s model is %0.2f%%' % (model, score * 100)) # Classifiers names = [ "Logistic Regression", "Logistic Regression with Polynomial Hypotheses", "Linear SVM", "RBF SVM", "Neural Net", ] classifiers = [ LogisticRegression(), make_pipeline(PolynomialFeatures(3), LogisticRegression()), SVC(kernel="linear", C=0.025), SVC(gamma=2, C=1), MLPClassifier(alpha=1), ]
 # iterate over classifiers models = [] trained_classifiers = [] for name, clf in zip(names, classifiers): scores = [] for train_indices, test_indices in cv.split(X): clf.fit(X[train_indices], y[train_indices].ravel()) scores.append( clf.score(X_test, y_test.ravel()) ) min_score = min(scores) max_score = max(scores) avg_score = sum(scores) / len(scores) trained_classifiers.append(clf) models.append((name, min_score, max_score, avg_score)) fin_models = pd.DataFrame(models, columns = ['Name', 'Min Score', 'Max Score', 'Mean Score'])
 fin_models.sort_values(['Mean Score']).head()
名前最小スコアMax Score 平均スコア
2 Linear SVM 0.793296 0.821229 0.803352
0 ロジスティック回帰0.826816 0.860335 0.846927
4 ニューラルネット0.826816 0.860335 0.849162
1 Logistic Regression with Polynomial Hypotheses 0.854749 0.882682 0.869274
3 RBF SVM 0.843575 0.888268 0.869274

Ok, so our experimental research says that the SVM classifier with a radial basis function (RBF) kernel performs the best. Now, we can serialize our model and re-use it in production applications.

 import pickle svm_model = trained_classifiers[3] data_path = os.path.join(os.getcwd(), "best-titanic-model.pkl") pickle.dump(svm_model, open(data_path, 'wb'))

Machine learning is not complicated, but it's a very broad field of study, and it requires knowledge of math and statistics in order to grasp all of its concepts.

Right now, machine learning and deep learning are among the hottest topics of discussion in Silicon Valley, and are the bread and butter of almost every data science company, mainly because they can automate many repetitive tasks including speech recognition, driving vehicles, financial trading, caring for patients, cooking, marketing, and so on.

Now you can take this knowledge and solve challenges on Kaggle.

This was a very brief introduction to supervised machine learning algorithms. Luckily, there are a lot of online courses and information about machine learning algorithms. I personally would recommend starting with Andrew Ng's course on Coursera.

資力

  • Andrew Ng's course on Coursera
  • Kaggle datasets
  • A deep learning reading list
  • A list of free books on machine learning algorithms, data mining, deep learning, and related topics
  • 機械学習理論とその応用の紹介:例を含むビジュアルチュートリアル
Related: Machines and Trust: How to Mitigate AI Bias