ゼロから始める機械学習 第5回「学習データとテストデータ」

はじめに

この記事は、連載「ゼロから始める機械学習」 の5本目の記事となります。

前回「ロジスティック回帰」 では、アヤメの分類タスクを機械学習で解きました。

モデルには、NumPyで実装したロジスティック回帰を用いました。

前回残った課題

最後に述べたとおり

評価は未知のデータで行うべきであるにも関わらず、

学習と評価を同じデータを用いていましたね。

そこで、今回は学習データとテストデータについて考えていきます。

データの分割

そこで、評価のために未知のデータを用意したいところですが、

未知のデータで評価をすることは原理的にできませんね。

そこで、既存のデータを分割し一部を未知のデータとして扱います。これをテストデータと呼びます。一方で、残ったデータを学習用に用います。これを学習データと呼びます。

表にまとめると以下のようになります。

では、この機能を実装して評価を行いましょう。

実装

ということで、次回は学習データとテストデータの分割について考えます。

まずは準備です。

1
2
3
4
5
6
7
8
9
from sklearn.datasets import load_iris
import numpy as np
iris = load_iris()
X_org = iris.data
y_org = iris.target
# 問題の簡単化(前々回記事を参照)
idx = [y_org != 2]
X = X_org[idx][:,:2]
y = y_org[idx]

ここまでは前回までと同様です。データをロードし、データを加工しています。

さて、ここから学習データとテストデータを分割する関数train_test_splitを実装していきます。

1
2
3
4
5
6
7
8
9
10
def train_test_split(X, y, test_size=0.25, shuffle=True):
idx = np.arange(len(X))
if shuffle:
idx = np.random.shuffle(idx)
sep = int(len(X) * (1-test_size))
X_train = X[:sep]
X_test = X[sep:]
y_train = y[:sep]
y_test = y[sep:]
return X_train, X_test, y_train, y_test

順に解説していきます。まず引数を見ると

1
def train_test_split(X, y, test_size=0.25, shuffle=True):

となっておいます。

まず、引数shuffleに注目します。このオプションでshuffle=Falseを指定しない限り、データはシャッフルされた後に分割するようにします。

なぜなら、データが最初の時点で何らかの規則で並んでいる可能性があるためです。その場合、単純に分割するだけではデータに偏りが生じてしまい、正しく評価を行えません。

実際、irisもラベル単位でデータがかたまっています。

次に引数test_sizeをみましょう。これは、文字通りテストデータの比率を表しています。
つまり、test_size=0.3とした場合、

  • テストデータは30%
  • 学習データは残りの70%

となります。この比率については、十分に信頼できるテストデータ数となるように決めれば良いということになりますが、30%前後とすることが多いです。

次に引数X, yに着目しましょう。合わせて返り値を見ると

1
return X_train, X_test, y_train, y_test

となっており、Xyを同時に分割しています。

test_sizeによって分割の比率を決めたり、shuffleによって並び替えを行うため、Xyは個別に処理するのではなく、一度の関数呼び出しで処理する必要があります。

そのため、上記のようにX, yを受け取り、X_train, X_test, y_train, y_testを返す実装となっています。

さて、それでは学習をして評価を行ってみましょう。

実装は前回の記事とほぼ同じです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class LogisticRegression:
def __init__(self, n_feature=2):
self.w = np.random.rand(n_feature + 1) # バイアス項
self.eta = 1e-2 # 学習率
self.n_iter = 1000 # パラメータの更新回数
self.loss = []
def fit(self, x, y): # 学習
for i in range(self.n_iter):
self._update(x, y)

def predict(self, x): # 予測
x = np.c_[x,np.ones(len(x))] # バイアス項
return self._forward(x)

def _forward(self, x): # 内部用のメソッド。
d = np.dot(x, self.w)
return np.exp(d) / (1 + np.exp(d))

def _diff(self, x, y): # 内部用のメソッド。出力と正解の差を計算する。
diff = self._forward(x) - y
return diff

def _update(self, x, y): # 内部用のメソッド。パラメータを一回更新する。
x = np.c_[x,np.ones(len(x))] # バイアス項
self.w -= self.eta * np.dot(self._diff(x, y), x) # 内積を取りサンプル数の次元を消す

lr = LogisticRegression()
lr.fit(X_train, y_train) # 学習
pred = (lr.predict(X_test) > 0.5).astype(np.int) # 予測と評価
print (np.mean(pred == y_test)) # 平均正解率

おそらく100%に近い正解率が得られたでしょう。

これが正真正銘のモデルの性能といえます!

次回

これで基本的な機械学習の流れを理解できたのではないでしょうか。

実はこれまでに実装してきた

  • ロジスティック回帰
  • train_test_split

scikit-learnライブラリに実装されています。

勉強のためにNumPyを用いてきましたが、実際のシーンではscikit-learnを使うことも多いでしょう。そこで、次回はこれらの内容をscikit-learnを用いて実装し直してみます。

「scikit-learnの活用」

記事情報

  • 投稿日:2020年3月30日
  • 最終更新日:2020年3月31日

ゼロから始める機械学習 第4回「ロジスティック回帰」

はじめに

この記事は、連載「ゼロから始める機械学習」 の4本目の記事となります。

前回「手動でのルールベース」 では、アヤメの分類タスクを設定し、手動でのルールベースによって解きました。

手動でのルールベースには、特徴量が多苦なると実装が現実的に不可能になるという課題がありました。

そこで機械学習の出番となるわけです。といっても、わかりやすくするために今回はタスクの内容は変えません。しかしながら、作成するプログラムは他のタスクにも応用が効く汎用的な内容になっていることに注意してください。

さて、最も基本的な機械学習モデルの一つであるロジスティック回帰について学びましょう。

ロジスティック回帰

ロジスティック回帰は、回帰ではなく分類タスクを解くためのモデルです。

ロジスティック回帰は厳密には二値分類のモデルですが、多値分類に拡張することができるため、ライブラリなどで(多値にも対応した)分類モデルとして実装されているでしょう。

二値分類とは

文字通りデータを二つのラベル(種類)に分類するタスクのことです。

と言っても、ラベルは数値である必要はありません。

アヤメの分類問題のように品種Aか品種Bかといったラベルで問題ありません。

ではなぜ二値分類と呼ばれるかというと、アルゴリズム上は01かを分類をするためです。つまり、プログラマがどちらの数字がどのラベルに対応するかを決めてあげれば良いのです。

数式

ロジスティック回帰は以下のような式で表されます。

1
2
3
4
x: 入力
y: 出力
w: 重み(パラメータ)
i: i番目の特徴量

まず、最初に理解していただきたいことは、ロジスティック回帰の出力y
0~1の間に収まるということです。これに対して適当な閾値(例えば0.5)を設けて、閾値以上であれば1と分類、そうでなければ0と分類したとみなします。

そして、wという変数が導入されています。
これが重みやパラメータと呼ばれる値で、学習によってより良いwを求めていくことになります。

より良いwとは

これが意外と難しい問いです。

少なくとも、完璧に分類ができるようなwは良いwと言えそうです。

そこで、正解率を指標にとっても良さそうですが、ここでは以下のような誤差関数を考え、

この誤差関数の値が小さいほど、良いwであると考えます。

1
2
3
4
5
L: 誤差関数
x: 入力
y: 出力
t: 正解ラベル
k: k番目のサンプル

この関数はバイナリクロスエントロピーと呼ばれます。

なぜこの数式が出てくるかは省略しますが、最尤推定という考え方に基づいて導出が可能で、数学的なバックグラウンドがしっかりしていると考えていただければ良いです。

この数式は完璧な予測、すなわち

1
t=y

の時にL=0となり、それ以外ではL>0となります。

学習

では、具体的にwをどのように更新するのでしょうか。

勾配法という概念を用います。

勾配法では、誤差を減らすためにはwをどちらに動かせば良いかを考えます。

これはLwで微分した値にマイナスを掛けることで得られます。

その値に学習率と呼ばれる係数を与えて、wを修正します。

そして、修正は一度だけではなく何度も繰り返し行い、最終的n良いwを得ようとするのです。

実装

先にソースコードを載せます

1
2
3
4
5
6
7
8
9
from sklearn.datasets import load_iris
import numpy as np
iris = load_iris()
X_org = iris.data
y_org = iris.target
# 問題の簡単化(前回記事を参照)
idx = [y_org != 2]
X = X_org[idx][:,:2]
y = y_org[idx]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class LogisticRegression:
def __init__(self, n_feature=2):
self.w = np.random.rand(n_feature + 1) # バイアス項
self.eta = 1e-2 # 学習率
self.n_iter = 1000 # パラメータの更新回数
self.loss = []
def fit(self, x, y): # 学習
for i in range(self.n_iter):
self._update(x, y)

def predict(self, x): # 予測
x = np.c_[x,np.ones(len(x))] # バイアス項
return self._forward(x)

def _forward(self, x): # 内部用のメソッド。
d = np.dot(x, self.w)
return np.exp(d) / (1 + np.exp(d))

def _diff(self, x, y): # 内部用のメソッド。出力と正解の差を計算する。
diff = self._forward(x) - y
return diff

def _update(self, x, y): # 内部用のメソッド。パラメータを一回更新する。
x = np.c_[x,np.ones(len(x))] # バイアス項
self.w -= self.eta * np.dot(self._diff(x, y), x) # 内積を取りサンプル数の次元を消す
1
2
3
4
lr = LogisticRegression()
lr.fit(X,y) # 学習
pred = (lr.predict(X) > 0.5).astype(np.int) # 予測と評価
print (np.mean(pred == y)) # 平均正解率

課題

評価方法に問題あり

さて、作成したプログラムは99%以上の精度を達成できたと思います。

しかし、このプログラムは実際のデータに対してそれだけの精度が出るでしょうか。

実は、そうとは限らないのです。

「機械学習とは?」 でも学んだように、

学習は既知のデータを扱うのに対し、予測では未知のデータを扱うことになります。

つまり、評価は未知のデータで行うべきです

今回のプログラムでは、学習と評価を同じデータで行なっています

なぜ同じデータを使ってはいけないのか

人間の勉強にたとえましょう。あなたがテストの作成者だとして、テスト前に問題を公表するでしょうか?

するべきではないでしょう。なぜなら、受験者が中身を理解せずに問題と答えを丸暗記してきてしまうからです。

機械学習の評価もこれと全く同じです。私たちはプログラムに丸暗記をして欲しいわけではないですよね。

ということで、次回は学習データとテストデータの分割について考えます。

「学習データとテストデータ」

記事情報

  • 投稿日:2020年3月29日
  • 最終更新日:2020年3月31日

ゼロから始める機械学習 第3回「手動でのルールベース」

はじめに

この記事は、連載「ゼロから始める機械学習」 の3本目の記事となります。

前回「Google Colarboratoryの使い方」 では、Google Colab環境の紹介をしました。

今回の記事でもGoogle Colab環境を用いるので準備がまだの方は、前回の記事を参考にしてください。

ローカルにJupyter環境があり、適宜読み替えられる方はJupyterでも問題ありません。

ルールベースとは

「機械学習とは?」の復習となりますが、

ある解きたいタスクに対して、

  • 人間がルールを考えるのが、ルールベース
  • コンピュータがルールを構築するのが、機械学習
    ということになります。

そのため、機械学習を学ぶ際にいきなり機械学習の実装に入るのではなく、ルールベースのプログラムを実装すると流れが理解しやすいです。

そこで、この記事ではルールベースでタスクを解きます。

タスク

フィッシャーのアヤメと呼ばれるデータを使います。

フィッシャーのアヤメは、あるアヤメに関する「がくの長さ」「がくの幅」「花弁の長さ」「花弁の幅」といった情報から、そのアヤメが3種類のアヤメのうちどれであるかを当てるタスクです。

データの詳細はこちらを参照してください。

公式ページからデータをダウンロードしても良いのですが、scikit-learnというライブラリ経由でダウンロードができるため、今回はその手法をとります。

scikit-learnについては連載の最後で取り扱いますが、それまでは例外的に今回を除き敢えて使わずに実装します)

実践

さて、いよいよ実装にうつりましょう。

1
2
3
4
from sklearn.datasets import load_iris
iris = load_iris()
X_org = iris.data
y_org = iris.target

iris.dataには4種類の特徴量が、iris.targetには品種を表す番号が格納されています。

それぞれをX_org, y_orgに代入しました。

続いて、データの少し加工を加えます。

というのも条件分岐をわかりやすくするために、

  • 分類する種類数を3から2に変更
  • 使う特徴量を4から2に変更

します。

1
2
3
idx = [y_org != 2]
X = X_org[idx][:,:2]
y = y_org[idx]

上記のコードの処理がわからない方は、NumPyのスライスについて復習してください。

1
import matplotlib.pyplot as plt

グラフ描画ライブラリをインポートしました。

1
2
3
4
5
6
7
colors_true = ['r' if i==0 else 'b' for i in y]
fig = plt.figure()
plt.scatter(*X.T, c = colors_true)
ax = fig.add_subplot(111)
ax.set_xlabel(iris.feature_names[0])
ax.set_ylabel(iris.feature_names[1])
plt.show()

データの散布図を書いています。

品種1を赤色、品種2を青色で示しています。

plt.scatterに引数cとして、色を指定するリストを渡しています。
rは赤、bは青を意味します)

これから、正解の品種のリストcolors_trueを使わずに、

試行錯誤しながらルールベースで同じリストを作成します。

まず、最初にcolorsを作っています。

これは、全ての要素が文字列のgのリストです。

このまま、plt.scattergを指定すると、緑のマーカーで描画されます。

これらを適切に赤や青に振り分けていきましょう。

先ほどのグラフを見ると

  • 横軸(sepal.length)が大きい場合は青、小さい場合は赤
  • 縦軸(sepal.width)が大きい場合は赤

と言えそうです。これを実装します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
colors = ['g'] * len(y)
for i in range(len(y)):
if X[i][0] > 5.8:
colors[i] = 'b'
if X[i][0] < 4.8:
colors[i] = 'r'
if X[i][1] > 3.4:
colors[i] = 'r'
fig = plt.figure()
plt.scatter(*X.T, c = colors)
ax = fig.add_subplot(111)
ax.set_xlabel(iris.feature_names[0])
ax.set_ylabel(iris.feature_names[1])
plt.show()

うまくいったようです。

さて、残った緑の点にも対処しましょう。

これはelseを使うことで、ルールを書けますね。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
colors = ['g'] * len(y)
for i in range(len(y)):
if X[i][0] > 5.8:
colors[i] = 'b'
elif X[i][0] < 4.8:
colors[i] = 'r'
elif X[i][1] > 3.4:
colors[i] = 'r'
else:
if X[i][0] > 5.4:
colors[i] = 'b'
if X[i][1] > 3.2:
colors[i] = 'r'
fig = plt.figure()
plt.scatter(*X.T, c = colors)
ax = fig.add_subplot(111)
ax.set_xlabel(iris.feature_names[0])
ax.set_ylabel(iris.feature_names[1])
plt.show()

もう少しです。さらにネストを深くします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
colors = ['g'] * len(y)
for i in range(len(y)):
if X[i][0] > 5.8:
colors[i] = 'b'
elif X[i][0] < 4.8:
colors[i] = 'r'
elif X[i][1] > 3.4:
colors[i] = 'r'
else:
if X[i][0] > 5.4:
colors[i] = 'b'
elif X[i][1] > 3.2:
colors[i] = 'r'
else:
if X[i][0] > 5.0:
colors[i] = 'b'
elif X[i][1] > 2.7:
colors[i] = 'r'
else:
colors[i] = 'b'
fig = plt.figure()
plt.scatter(*X.T, c = colors)
ax = fig.add_subplot(111)
ax.set_xlabel(iris.feature_names[0])
ax.set_ylabel(iris.feature_names[1])
plt.show()

やりました。うまくいっていそうです。

1
colors_true == colors

Trueが返ってきました。つまり、ルールベースで完璧に分類ができました。

課題

さて、目的を達成しましたが

ここでルールベースの課題を考えましょう。

最大の問題点は、特徴量が多苦なると実装が現実的に不可能になるためです。

今回の場合、特徴量の数を2種類でした。

しかし、これが3,4と増えたらどうでしょうか。

段々とグラフが複雑になったり、グラフの枚数を増やす必要が出てきます。

3,4くらいなら、まだそれでも対応可能かもしれません。

しかし 現実のタスクでは特徴量は数万を超えることもあります。

そうなると、グラフで描画しながら人間がルールを考えていく方法には無理がありそうです。

次回

そこで、機械学習の出番となるわけです。ルールを自動でコンピュータに獲得してもらいましょう。

「ロジスティック回帰」

記事情報

  • 投稿日:2020年3月28日
  • 最終更新日:2020年3月29日

ゼロから始める機械学習 第2回「Google Colarboratoryの使い方」

はじめに

この記事は、連載「ゼロから始める機械学習」 の2本目の記事となります。

前回「機械学習とは?」 では、機械学習の概要やプログラミングとの関連性について説明しました。

機械学習を学ぶ上ではプログラミングはほぼ必須と言えるでしょう

そして、今後の記事ではPythonプログラムを動かしながら学んで行くことになります。

この記事では、そのための環境構築を行います。

環境構築は学習者の悩みのタネ

皆さんもご存知の通り、プログラミングにおいては環境構築のハードルが高いですね。

初学者向けの言語として認知されているPythonでも同様のことが言えます。

環境構築から学ぶことも多いのですが、

あれこれ勉強しようと手を出してしまうと混乱してしまい、学習効率も落ちます。

そこで、最もおすすめな環境がGoogle Colaboratoryです。

Google Colaboratoryとは

(以下Google Colab

https://colab.research.google.com/
Googleが提供しているクラウドで実行されるJupyter Notebook環境です。
Googleアカウントを持っていれば、誰でも無料で利用できます

なぜ初学者におすすめか?

メリットはいくつもあるのですが、特に大きな理由を4つ紹介します。

  1. エディタとしても実行環境としても使えるため

    Google Colab(正確にはJupyter Notebook)はインタラクティブな実行環境です。

    つまり、エディタや実行環境を用意・管理する必要がありません。

    Visual Studio Codeなどのエディタは非常に便利ですが、初学者にとっては多機能でありすぎることがデメリットにもなり得ます。

    その点、Google Colabはシンプルな構成となっており、素早く習得することができます。

    機械学習やプログラミングに慣れてきたタイミングで、自分にあったエディタを探すという方針で良いと思います。

  2. ライブラリのインストールが不要なため

    Google Colabの環境では主要なライブラリは標準でインストールされています。そのためライブラリを管理する必要はありません。

    一部、インストールされていないライブラリもありますが、セッションごとに一時的にインストールことが出来ます。

    インストールした内容はセッションごとにリセットされるため、環境を壊してしまう心配もありません。

  3. インタラクティブに操作ができるため

    ノートブック形式であるため、変数の中身やタイプを確認しながら実装を進められます。

    初学者のうちはコードを1行ずつ追いながら、それぞれでどういった処理がされているかを理解することが大切です。

    また、セルを一つずつ実行できるので、エラーが発生した際に原因を特定しやすいです。

  4. ローカルPCのスペックを問わないため

    Google ColabはWebアプリとして動作します。そのため、ローカルPCのスペックが低くても構いません。Google ColabではGPUも使えてしまいます。

    またソースコードがクラウド上に保存されるため、一旦中断した後に違う端末から再開することもできます。

実践

アクセス

それでは実際に動かしてみましょう。まずは、下記のリンクからGoogle Colabにアクセスしてください。

https://colab.research.google.com/

以下のようなページが出てくると思うので「ファイル」「ノートブックを新規作成」をクリック。

ここで、Googleへのログインを求められた場合はログインしてください。

画像のような画面が現れると思います。

画像中の長方形の部分はセルと呼ばれ、ここにコードを書くことになります。

試しにセルに以下のコードを貼り付けてみてください。

1
2
var = 1+2
print (var)

そして、セルをクリックした状態で

[Shift]キー+[Enter]キー

を押してください。結果が出力されるはずです。

「+コード」をクリックすると、選択しているセルの下に新たなセルを追加できます。

以上がGoogle Colabの基本的な使い方となります。

ノートブックは自動でGoogle Driveに保存されます。

ライブラリのインポート

Google Colabには主要なライブラリはインストール済みでしたね。

その確認も兼ねて、今後の解説でも使うNumPymatplotlibをインポートし、動かしてみましょう。

Numpy

数値計算に用いるライブラリです。

Pythonではデファクトスタンダードとなっているライブラリです。

この連載でも、NumPyを使って機械学習の実装をしていきます。

ここで、少しNumPyを使ってみましょう。

ライブラリを使う際は、まずインポートが必要です。

次のコードをセルに貼り付けて実行してみましょう。

1
import numpy as np

先ほどと違い、何も出力されませんがそれで問題ありません。

今度は0~9までの値が格納されたリストを作成してみましょう

1
2
A = np.arange(10)
print (A)

結果

1
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

さて、リストAの中身をシャッフルしてみましょう。

どのように実装するのが良いでしょうか。

実は、こういった基本的な処理であれば、NumPyrandom.shuffleとして実装されているため自分で実装する必要はありません。

1
2
np.random.shuffle(A)
print (A)

random.shuffleは今後使うことになるので、ぜひ覚えておいてください。

Matplotlib

matplotlibはグラフを描画のためのライブラリです。

このライブラリも今後使っていくことになります。

1
import matplotlib.pyplot as plt

ためしに先ほどのリストの中身を折れ線グラフで表示してみましょう。

1
plt.plot(A)

今後の記事では散布図を描画するために利用します。

次回

「手動でのルールベース」

次回はいよいよ、プログラムを組んで実際にデータを処理してみましょう。

まずはルールベースによってデータを判別するプログラムを作成します。

記事情報

  • 投稿日:2020年3月27日
  • 最終更新日:2020年3月29日

ゼロから始める機械学習 第1回「機械学習とは?」

連載「ゼロから始める機械学習」でお知らせしたように、「ゼロから始める機械学習」と題して

初学者向けに機械学習の解説を書いていきたいと思います。

目次

  • はじめに
  • スパムフィルタ
  • 機械学習の用語
  • その他の機械学習の例
  • プログラミングとの関係

はじめに

機械学習には大きく分けて、3つの種類があります。

  • 教師あり学習
  • 教師なし学習
  • 強化学習
    この3つを体系的に理解しようとすると、とても複雑です。

そこで、この解説では最も基本的で一般的な教師あり学習にフォーカスを当てます。

まず、身近な機械学習(教師あり学習)の例としてスパムフィルタを見ていきましょう!

スパムフィルタ

スパムフィルタの目的

皆さんの中でメールを使ったことがない人はいないでしょう。そして、メールにはスパムフィルタと呼ばれる機能があるのをご存知でしょう。

メールアドレスを持っていると、スパムメール(迷惑メールのこと)を受信することがよくあります。受信する全てのメールに対して、利用者が

これは大事なメールだから読もう

これはスパムメールだから捨てよう

とわざわざ見分けているととても手間ですよね。そういった手間を省くためにスパムフィルタが存在するわけです。

スパムフィルタはプログラムでできている

では、スパムフィルタはどのような仕組みで動いているのでしょうか。

もちろん、誰かが手動で振り分けをしているわけではなく、

プログラムが自動で識別をしています

スパムフィルタを作るとしたら?

その際、あなたがプログラマだったらどのようにプログラムを組むでしょうか。

1
2
3
- 儲かる
- 会いたい
- 久しぶり

といった典型的なスパムメールのキーワードを列挙してみて、

それが含まれるかどうかを判定するプログラムを組むと良さそうです。

メンテナンスが必要

しかし、そのようにして作ったプログラムはメンテナンスが大変です。

キーワードは最初に考えたものだけでは十分ではなく、追加していく必要があるでしょう。

また、本当に「久しぶり」という単語が含まれるメールは全てスパムだと言えるでしょうか?

「久しぶり」という単語と合わせて、「アドレスを変えました」などのフレーズも出てきたらスパムの可能性は高そうです。

だんだんとルールが複雑に・・・

このようにしていくと、プログラムの条件分岐が増えてとても複雑になってしまいます。

こういった課題を解決するのが機械学習です。

コンピュータにルールを発見させる

では、機械学習だとこの課題をどうクリアできるのでしょうか。

機械学習の場合、人間がルールを考えてプログラムをする必要がありません

コンピュータに大量のデータを与えることで、そこからルールを発見することを期待します。

スパムフィルタのための機械学習

そういったルール発見を自動化する学問を機械学習だと思ってください。

そして、それを実現する仕組みのことを機械学習モデルと呼びます。

機械学習モデルには、事前に以下の情報を与えます。

  • メールの文章
  • そのメールがスパムであるかどうか

機械学習モデルはこれらの情報からルールを獲得します。この過程を学習 と呼びます。

これらの情報は事前に与えることに注意してください。つまり、実戦投入する前の練習ということです。

学習を終えた機械学習モデルに、

  • 未知のメールの文章

を与えると、それがスパムメールであるかどうかを判定することができます!

この処理を予測(推論) と呼びます。

この時、最も重要なのはメールの内容が未知であっても問題がないということです。

つまり、スパムメールの内容を丸暗記しているわけではないのです。

機械学習は応用が効く

機械学習のアプローチは、人間がルールを考えるアプローチとは全く考え方が異なることがお分かり頂けたでしょうか。

また、機械学習は非常に応用が効きます。

新しいデータ

例えば、スパムフィルタを作成してから時間がたち、時代の変化とともにスパムメールの傾向が変わってきたとしましょう。スパムフィルタの精度はだんだんと劣化していくでしょう。

しかし、機械学習の場合は新しいデータを利用して、再度学習を行えば良いのです。ルールベースの場合はそうはいきません。再びキーワードの選定や、条件分岐の習性が必要になるでしょう。

類似したタスクへの適用

機械学習を使って英語向けのスパムフィルタを組んでしまえば、他の言語についてもプログラム自体を大きく作り直す必要がない場合もあるでしょう。

なぜなら、ルールを記述せずにデータからルールを学んでいるので、データを丸ごと変えればそのデータでのスパムメールの傾向を自動で獲得できるからです。

機械学習の用語

では、スパムフィルタから一般化させて、機械学習の用語を整理します。

学習と予測

機械学習を利用する際には二つのステップがありましたね。

  1. 学習(ルールを獲得)
  2. 予測(未知のメールを判別)

説明変数と目的変数

機械学習モデルの入力(メールの文章)を

  • 説明変数または特徴量

出力(そのメールがスパムであるかどうか)を

  • 目的変数またはラベル

と呼びます。

その他の機械学習の例

スパムフィルタは、機械学習の成功例としてはかなり古い部類です。

現代では、かなり多くの用途で機械学習が用いられています。

  • 文字認識
  • 顔認識
  • 音声認識
  • クレジットカードの不正利用検知
  • 画像認識
  • 自動運転
  • チャットボット

他にもまだまだありますし、今後もさらに増えていくと考えられます。

プログラミングとの関係

さて、これからの記事ではプログラミングを用いながら機械学習を学んでいきます。

その理由は、もうお分かりですね?

機械学習は、データを元にルールを自動で獲得するシステムなので、

基本的にはプログラム上で実現されることになります。

そのため、機械学習を学ぶ際はプログラムを動かしながら学ぶのが最も効率が良いのです。

次回

機械学習を学ぶためにプログラミングをする上で、最初のハードルとなるのは環境構築です。

その点で、Google Colaboratoryは機械学習の初学者にとってメリットが満載の環境です。

そこで、次回(第2回)のテーマは「Google Colaboratoryを用いた環境構築」として、

環境構築の方法について解説します。

「Google Colaboratoryの使い方」

記事情報

  • 投稿日:2020年3月26日
  • 最終更新日:2020年3月27日

連載「ゼロから始める機械学習」

はじめに

近年、機械学習という技術が注目を集めています。そして

機械学習を始めたい!

と思っている方も多いはず。そこで、

機械学習の超入門記事を作ります。とにかく丁寧に書きます!

タイトルは、「ゼロから始める機械学習」 です!

6回に渡って連載記事にします。

対象とする方

以下のような方にオススメです。

  • 機械学習の基本を知りたい
  • 機械学習の実装を少しでもできるようにしたい
  • Python学習のゴールとして機械学習を使えるようにしたい
  • エンジニアとしての技術を広げるために、機械学習の概略を理解したい
  • 機械学習を勉強したことはあるが、ライブラリを使っただけで結局よくわからなかった

前提とするスキルは、

何らかのプログラミング言語を触ったことがあること

です。

Pythonという言語を使って進めていきますが、

何らかの言語の経験があれば、問題なく理解できるように丁寧に書きます!

ゴール

簡単な機械学習プログラムの実装ができる

レベルをゴールにします。

連載記事の予定

第1回 機械学習とは

目標

  • 機械学習の概要を理解する
  • 機械学習とプログラミングの関係を理解する

第2回 Google Colaboratoryの使い方

目標

  • Google Colaboratoryの概要を理解する
  • Google Colaboratoryを使ってプログラミングができるようになる

第3回 「手動でのルールベース」

目標

  • 機械学習における分類タスクを理解する
  • ルールベースのプログラムを実装する

第4回 「ロジスティック回帰」

目標

  • ロジスティック回帰モデルの概要を理解する
  • ロジスティック回帰モデルを実装する

第5回 「学習データとテストデータ」

目標

  • 学習と評価の概念を理解する
  • 学習データとテストデータの分離をする必要性を理解する
  • データを分離するプログラムを実装する

第6回 「scikit-learnの活用」

目標

  • scikit-learnの概要を理解する
  • scikit-learnでこれまでのタスクを解く

終わりに

他にも様々なテーマでまとめ記事を書いているのでよろしければご覧ください。

まとめ記事の一覧

記事情報

  • 投稿日:2020年3月25日
  • 最終更新日:2020年5月23日

Falconの使い方

Falcon

PythonのWebアプリケーションフレームワークの一つです。

コードを動かしてみよう

インストール

Falconは標準ライブラリではありません。

pipを使っている場合は、以下のようにしてインストールしてください。

1
pip install falcon

サンプルコード

localhost:8000/textにアクセスするとtext/plainで、

localhost:8000/jsonにアクセスするとapplication/jsonでレスポンスを返却するプログラムを作成します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

import falcon
import json
from wsgiref import simple_server

class TextResource(object):
def on_get(self, req, resp):
resp.status = falcon.HTTP_200
resp.body = ('hello')
resp.content_type = ('text/plain')

class JsonResource(object):
def on_get(self, req, resp):
resp.status = falcon.HTTP_200
msg = {
"message": "hello"
}
resp.body = json.dumps(msg)

app = falcon.API()
app.add_route('/text', TextResource())
app.add_route("/json", JsonResource())

if __name__ == "__main__":
httpd = simple_server.make_server('127.0.0.1', 8000, app)
httpd.serve_forever()

wsgirefとは

PythonによるWebサーバソフトウェアとWebアプリケーションとの標準インターフェースを定めたものがWSGIです。
そして、wsgirefはWSGI仕様のリファレンス実装(実装例)です。

PythonでWebサーバを立てるその他の方法

http.server(旧SimpleHTTPServer)の使い方

Flaskの使い方

Djangoの使い方

記事情報

  • 投稿日:2020年3月24日
  • 最終更新日:2020年3月24日

ABC159D Banned K

問題

https://atcoder.jp/contests/abc159/tasks/abc159_d

方針

  • ボールを除かない場合の選び出す方法をかぞえあげる
  • あるボールを除いた場合を考える
    • そのボールと同じ値が書かれているボールが全部でD個とした場合、そのボールを除くことでD-1通りの組み合わせが失われる。

ポイント

  • 要素の数え上げにはcollections.Counterを使う。
  • 「どの値のボールが何個あるか」は辞書にしておく。

コード

1
2
3
4
5
6
7
8
9
10
11
12
13
import collections
def C(n):
return n * (n-1) // 2
N = int(input())
A = list(map(int,input().split()))
c = collections.Counter(A)
d = {}
sm = 0
for k,v in c.most_common():
d[k] = v
sm += C(v)
for a in A:
print (sm - d[a] + 1)

記事情報

  • 投稿日:2020年3月23日
  • 最終更新日:2020年3月23日

AGC043A Range Flip Find Route

問題

https://atcoder.jp/contests/agc043/tasks/agc043_a

方針

公式の解説にもあるように、
どのような操作をしても必ず1しか減らせず、1減らすような操作は必ず存在します。
そこで、動的計画法を用いる。

ポイント

  • スタートマスの1マス左および上のバスはコスト0、それ以外のマスは十分大きい値(1000)とする
  • 白マスから黒マスに移動する際にコストを+1する、ただしスタートマスが黒マスの場合も+1する

そこで、窓の和を求める際に窓の中の要素を全て足すのではなく、一つ隣の窓の和との差分を計算することで、計算量を削減する。

コード

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
H, W = map(int,input().split())
board = []
for h in range(H):
board.append(input())

dp=[[1000 for i in range(W+1)] for j in range(H+1)]
dp[0][1] = 0
dp[1][0] = 0

for h in range(H):
for w in range(W):
dp[h+1][w+1] = min(
dp[h][w+1] + (board[h][w]=='#' and (h==0 or board[h-1][w]=='.')),
dp[h+1][w] + (board[h][w]=='#' and (w==0 or board[h][w-1]=='.'))
)

print (dp[-1][-1])

記事情報

  • 投稿日:2020年3月22日
  • 最終更新日:2020年3月22日

CSVファイルをpandasで読み込み、scikit-learnで学習させる

概要

この記事では、csvデータをpandasで読み込み、scikit-learnで学習させる方法について解説します。

連載「scikit-learnで学ぶ機械学習」を始めます)

では、sklearn.datasetsのデータを使ってscikit-learnの学習方法について学びました。

しかし、実際に機械学習を行うと思った場合、csvデータを利用する必要もあるはずです。

この記事では、csv形式で与えられるフィッシャーのアヤメデータを学習します。

データのダウンロード

まず、作業ディレクトリを作成してください。

こちらのリンクから、iris.dataをダウンロードしてください。拡張子は.dataとなっていますが、中身はcsvフォーマットで書かれています。

ダウンロードしたデータを作業ディレクトリに配置してください。

準備はこれで完了です。

コード

先ずは、今回動かすコードを見てみましょう。このコードを1行ずつ紹介していきます。

1
2
3
4
5
6
7
8
9
10
11
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
df = pd.read_csv('./iris.data', header = None)
arr = df.values
X = arr[:,:-1]
y = arr[:,-1]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
clf = MLPClassifier()
clf.fit(X_train, y_train)
print (clf.score(X_test, y_test))

pandasのインポート

1
import pandas as pd

pandasはデータ分析用のライブラリで、表形式のデータを扱うことができます。

train_test_splitのインポート

後ほど、学習データとテストデータの分割に用いるので、インポートします。

1
from sklearn.model_selection import train_test_split

ニューラルネットワークのインポート

1
from sklearn.neural_network import MLPClassifier

今回はモデルとしてニューラルネットワークを用います。

csvをロードする

1
df = pd.read_csv('./iris.data', header = None)

pandasではread_csv関数を用いて、csvをロードすることができます。

第一引数にcsvファイルまでのパスを記します。

iris.dataにはヘッダーがないため、header=Noneを指定しています。

ヘッダーを含むデータの場合は、指定する必要がありません。

データの確認をする

では、データをどのような形式となっているのでしょう。

1
2
>>> type(df)
pandas.core.frame.DataFrame

pandasDataFrameと呼ばれる二次元の表形式のデータとなっています。

あなたが、ノートブックや対話モードでスクリプトを実行している場合、以下のコマンドを実行することで、テーブルの先頭を確認することができます。

1
head()

numpy.ndarrayへの変換

scikit-learnではpandasのDataFrameを直接扱うことができません。

そこで、まずpandas.Dataframenumpy.ndarrayに変換します。

これはvalues()メソッドで行うことができます。

1
arr = df.values

データの型を確認しましょう。

1
2
>>> type(arr)
numpy.ndarray

特徴量とラベルの定義

フィッシャーのアヤメのデータは、アヤメの「がくの長さ」「がくの幅」「花弁の長さ」「花弁の幅」からアヤメの種類を分類するためのデータです。

データを見るとわかりますが、

  • ラベル・・・最後の一列
  • 特徴量・・・それ以外

となっていることがわかります。

そこでスライスを行い、特徴量(X)とラベル(y)を作成します。

1
2
X = arr[:,:-1]
y = arr[:,-1]

学習データとテストデータの分割

1
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

train_test_splitを使ってデータを学習用データとテストデータに分割しています。それぞれに目的変数と説明変数があるため、返却されるオブジェクトは4つとなります。test_sizeは分割の比率を決めるパラメータで、ここでは30%をテストデータに、残りの70%を学習用データとしています。

ニューラルネットワークのインスタンスを作成

1
clf = MLPClassifier()

学習

1
clf.fit(X_train, y_train)

予測およびスコアの計算

1
print (clf.score(X_test, y_test))

おわりに

MENTAというサービスでプログラミング学習のサポートをしています。競技プログラミングについてもサポートできるので、ご興味がある方はぜひMENTAのDMでご連絡いただければと思います。

記事情報

  • 投稿日:2020年3月21日
  • 最終更新日:2022年1月8日