教師あり学習1　教師あり学習（分類）の基礎

[Aidemy](https://aidemy.net/)　2020/9/30
#　はじめに
　こんにちは、んがょぺです！バリバリの文系ですが、AIの可能性に興味を持ったのがきっかけで、AI特化型スクール「Aidemy」に通い、勉強しています。ここで得られた知識を皆さんと共有したいと思い、Qiitaでまとめています。以前のまとめ記事も多くの方に読んでいただけてとても嬉しいです。ありがとうございます！
　今回は、教師あり学習の一つ目の投稿になります。どうぞよろしくお願いします。

＊本記事は「Aidemy」での学習内容を「自分の言葉で」まとめたものになります。表現の間違いや勘違いを含む可能性があります。ご了承ください。

今回学ぶこと
・教師あり学習の概要
・教師あり学習（分類）の種類

#教師あり学習（分類）について
##教師あり学習（分類)とは
・前提として、教師あり学習とは「学習データと正解（教師）データを与えて正解するまで思考する方法」であり、これを通じて未知のデータを予測するのが目的。
・教師あり学習は「分類問題」と「回帰問題」に分けられる。今回は分類問題について見ていく。
・分類問題とは、__「カテゴリ別に分けてあるデータを学習し、未知のデータのカテゴリ(離散値)を予測する」__物をいう。例えば、「０〜９の手書き文字認識」「画像に写っているものの識別」「文章の著者予測」「顔写真の男女識別」などが挙げられる。

・分類問題は__「二項分類」「多項分類」__に分けられる。
・二項分類は、男女認識のように、一方のグループに属しているかいないかで分類するもの。クラス間を直線で識別できる場合もある（線形分類）。
・多項分類は、数字の認識のように、分類できるクラスが多数あるもの。

##機械学習の流れ
・データの前処理→アルゴリズムの選択→モデルの学習→モデルによる予測

・教師あり学習（分類）では、アルゴリズムの選択で「分類アルゴリズム」を選択する。


##データを作成する
・分類に適したデータを作成するには、make_classification()メソッドをインポートして使う。
・__X,y = make_classification(n_samples=データの個数,n_classes=クラス数（デフォ値：2）,n_features=特徴量,n_redundant=余分な特徴量,random_state=乱数のseed)__
*変数Xはデータそのものを、yはクラスのラベルを格納する。
*特徴量とは、クラスを分ける特徴になりうるものの個数のことである。男女認識の例で言えば、「髪の長さ」「身長」「肩幅」を特徴として分けた時、実際の分類で使う物を前者２つとした場合、n_featuresは2,n_redundantは1となる。

```python
from sklearn.datasets import make_classification
#データ数50、クラス数3、特徴量2、余分な特徴量1、seed0のデータを作成
X,y=make_classification(n_samples=50,n_classes=3,n_features=2,n_redundant=1,random_state=0)
```

##サンプルデータの取得
・scikit-learnライブラリ(sklearn)に用意されているサンプルデータセットを呼び出すことができる。

```python
#アヤメのサンプルであるIrisデータを呼び出す。

#モジュールのインポート（Irisデータを取得するためのdataset,ホールドアウト法を使うためのtrain_test_splitをsklearnからインポート）
from sklearn import datasets
from sklearn.model_serection import train_test_split
import numpy as np

#Irisデータを取得
iris=datasets.load_iris()

#トレーニングデータとテストデータに分ける（ホールドアウト法:testの割合30％）
X=iris.data[:,[0,2]]  #Irisの特徴量のうち、0、2列目（「がくの長さ」「花びらの長さ」）
                      #（＝学習データ）
y=iris.target         #Irisのクラスラベル（＝正解の品種が書かれた教師データ）

train_X,test_X,train_y,test_y = train_test_split(X,y,test_size=0.3,random_state=0)
```

##モデルの構築
・学習し、予測するもののことをモデルという。scikit-learnによって、Ruby on Railsのように用意されたモデルを呼び出して、それに学習や予測を行わせることができる。
・モデルの作成：　__モデル()__
・学習：　__モデル名.fit（train学習データ,train教師データ）__
・予測：　__モデル名.predict(データ）__

```python
#LogisticRegression（ロジスティック回帰）というモデルをインポートする。
from sklearn.liner_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_classification
#データの作成（データ数50、2クラス、特徴量3）とtrainとtestに分類
X,y = make_classification(n_samples=50,n_classes=2,n_features=3,n_redundant=0,random_state=0)
train_X,test_X,train_y,test_y = train_test_split(X,y,random_state=0)
#モデルの作成、学習、予測
model = LogisticRegression(random_state=0)
model.fit(train_X,train_y)
pred_y = model.predict(test_X)
print(pred_y) #[1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 1 1 1]
print(test_y) #[1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 1 1 0 1 1 1]
```

#分類のやり方（クラス間の境界線を作る）
##今回扱う六種類
・__ロジスティック回帰__：境界線が直線→線形分類のみ。汎化能力が低い。
・__線形SVM__：境界線が直線→線形分類のみ。汎化能力が高い。学習・予測が遅い。
・__非線形SVM__：非線形分類を線形分類に直して、線形SVMとして処理する。
・__決定木__：データの要素ごとにクラスを決定。外れ値に左右されにくい。線形分類のみ。汎化されない。
・__ランダムフォレスト__：ランダムなデータに決定木を用いてクラスを決定。非線形分類も可能。
・__k-NN__：予測データと類似している教師データを抽出し、最も多かったクラスを予測結果として出力する。学習コストが0。高い予測精度。データ量が増えると低速化。

##ロジスティック回帰
・境界線が直線なので、線形分類のみ扱える。境界線がデータに寄り添ってしまうため汎化能力が低い。
・モデル作成は__LogisticRegression()__で行い、学習はfit()、予測はpredict()で行う。詳しくは前々項参照。正解率が知りたい時は__model.score(pred_y,test_y)__で行う。

・ここでは、モデルの予測結果をグラフ（散布図）に表し、色分けして可視化する。
・（復習）散布図の作成：plt.scatter(x軸のデータ,y軸のデータ,c=[リスト],marker="マーカーの種類",cmap="色系統")
・下記に出てくる__np.meshgrid(x,y)__は、座標（x,y）を行列に変換して渡す関数。

```python
#グラフを作るためのpltと、座標を取得するためのnpをインポート
import matplotlib.pyplot as plt
import numpy as np
#plt.scatterで散布図の作成（学習データXの0列目をx軸、1列目をy軸とする）
plt.scatter(X[:,0],X[:,1],c=y,marker=".",cmap=matplotlib.cm.get_cmap(name="cool"),alpha=1.0)
#この次に指定するx軸（x1）、y軸（x2）の範囲指定
x1_min,x1_max = X[:,0].min()-1, X[:,0].max()+1
x2_min,x2_max = X[:,1].min()-1, X[:,1].max()+1
#np.meshgridで、グラフを0.02ずつ区切った箇所のx1、x2の交点のx座標をxx1、y座標をxx2に格納（np.arrange(最小値,最大値,間隔)）
xx1,xx2 = np.meshgrid(np.arange(x1_min,x1_max,0.02),np.arange(x2_min,x2_max,0.02))
#座標（xx1,xx2）の配列に対してmodelで予測し、plt.comtourfでその結果を描画
Z=model.predict(np.array([xx1.ravel(),xx2.ravel()]).T).reshape((xx1.shape))
plt.contourf(xx1,xx2,Z,alpha=0.4,cmap=matplotlib.cm.get_cmap(name="Wistia"))
#グラフの範囲、タイトル、ラベル名、グリッドの設定をして出力
plt.xlim(xx1.min(), xx1.max())
plt.ylim(xx2.min(), xx2.max())
plt.title("classification data using LogisticRegression")
plt.xlabel("Sepal length")
plt.ylabel("Petal length")
plt.grid(True)
plt.show()
```

##線形SVM
・境界線が直線→線形分類のみ。汎化能力が高い。学習・予測が遅い。
・SVMとは「サポートベクターマシン」のこと。サポートベクターは他クラスと距離が近いデータのことで、これらの距離が最も遠くなるように境界線が引かれるので、汎化されやすい。

・線形SVMは__LinearSVC()__で実装できる。それ以外については、ロジスティック回帰と同様に実装できる。

##非線形SVM
・非線形分類を線形分類に直して、線形SVMとして処理する。
・線形SVMに直すには「カーネル関数」を使う。
・非線形SVMは、__from sklearn.svm import SVC__でインポートした__SVC()__を使う。それ以外はロジスティック回帰と同じ。

##決定木
・データの要素ごとにクラスを決定する。外れ値に左右されにくい。線形分類のみ。汎化されない。
・__from sklearn.tree import DecisionTreeClassifier__でインポートした__DecisionTreeClassifier（）__を使う。

##ランダムフォレスト
・ランダムなデータの決定木を複数作成し、それぞれ分類した結果のうち最も多数だったクラスを結果として出力する。アンサンブル学習の一つでもある。非線形分類も可能。
・__from sklearn.ensemble import RandomForestClassifier__でインポートした__RandomForestClassifier()__を使う。

##k-NN
・予測データと類似している教師データをk個抽出し、最も多かったクラスを予測結果として出力する。学習コストが0。高い予測精度。データ量が増えると精度ダウンand低速化。
・__from sklearn.neighbors import KNeighborsClassifier__でインポートした__KNeighborsClassifier()__を使う。

#まとめ
・教師あり学習（分類）とは、データを学習させ、そのデータに基づいて分類を予測するものである。
・分類に適したデータを作成するには、make_classification()メソッドをインポートして使う。
・データを作成せずとも、scikit-learnライブラリ(sklearn)に用意されているサンプルデータセットを呼び出して使うことができる。（ex)アヤメのデータIris）
・学習し、境界線を予測するモデルには、ロジスティック回帰,線形SVM,非線形SVM,決定木,ランダムフォレスト,k-NNがあり、それぞれに特徴がある。

今回は以上です。ここまで読んでくださり、ありがとうございます。