Coursera 機械学習 - プログラミング課題2解答例
By Huy Van
課題について
今回の課題はLogistic Regression(分類)に関するものです。
https://www.coursera.org/learn/machine-learning/programming/ixFof/logistic-regression
ソースコードはgithubに上げました。
https://github.com/vanhuyz/coursera-ml/tree/master/machine-learning-ex2/ex2
問題1
Logistic regressionモデルで学生の過去の2つテスト結果から大学入試に合格・不合格を予測します。
学習データは以下の図の通りです。+は合格、◯は不合格です。
1. Sigmoid関数
Sigmoid関数は以下のように定義されています。
$$ g(z)=\frac{1}{1+e^{-z}} $$
注意したいのはzはスカラー、ベクトル、行列でもいいです。ベクトル・行列の場合は各要素を適応することになるます。
実装:
function g = sigmoid(z)
g = zeros(size(z));
g = 1 ./ (1 + exp(-z));
end
Octaveの**+**、exp演算子はもし行列と実数を計算するとき、自動に各要素に適応するようです。 / はそうになっていないのでちゃんと . をつけましょう。
2. Cost function and gradient
- Cost function:
$$ J(\theta) = \frac{1}{m}\sum_ {i=1}^{m}[-y^{(i)}\log(h_ \theta(x^{(i)}))-(1-y^{(i)})\log(1-h_ \theta(x^{(i)}))] $$
- Gradient:
$$ \frac{\partial J(\theta)}{\partial \theta_ j} = \frac{1}{m}\sum_ {i=1}^m (h_ \theta(x^{(i)})-y^{(i)})x_ j^{(i)} $$
実装: 理解しやすいためcost functionの計算とgradientの計算を分けています。
function [J, grad] = costFunction(theta, X, y)
m = length(y); % number of training examples
J = 0;
grad = zeros(size(theta));
% cost function
for i = 1:m
h = sigmoid(X(i,:) * theta);
J += -y(i)*log(h) - (1 - y(i))*log(1-h);
end
J = J / m;
% gradient
for j = 1:size(theta)
for i = 1:m
h = sigmoid(X(i,:) * theta);
grad(j) += (h - y(i)) * X(i,j);
end
end
grad = grad / m;
end
番外編:Gradientのベクトル化:
gradientベクトルを$\nabla$で記号すると、以下のようになります(予想です。僕がまだ証明しません。でも結果は正しいので合っているでしょう)
$$ \nabla J(\theta) = \frac{1}{m}X^T(g(X\vec \theta)-\vec y) $$
実装は簡単になり、速度も速くなります。
grad = X'* (sigmoid(X*theta) - y) / m
3. Learning parameters using fminunc
課題はありません。実装コードはすでに提供されます。
% Set options for fminunc
options = optimset('GradObj', 'on', 'MaxIter', 400);
% Run fminunc to obtain the optimal theta
% This function will return theta and the cost
[theta, cost] = fminunc(@(t)(costFunction(t, X, y)), initial_ theta, options);
@
部分はRubyのProc/lambdaみたいなものだと思います。
実行結果
Cost at initial theta (zeros): 0.693147
Gradient at initial theta (zeros):
-0.100000
-12.009217
-11.262842
Cost at theta found by fminunc: 0.203498
theta:
-25.161272
0.206233
0.201470
For a student with scores 45 and 85, we predict an admission probability of
0.776289
4.Evaluating logistic regression
求められた$\theta$の値を使って、学習データを再評価します(どのぐらい合っているのかを計算します)
function p = predict(theta, X)
%PREDICT Predict whether the label is 0 or 1 using learned logistic
%regression parameters theta
% p = PREDICT(theta, X) computes the predictions for X using a
% threshold at 0.5 (i.e., if sigmoid(theta'*x) >= 0.5, predict 1)
m = size(X, 1); % Number of training examples
p = zeros(m, 1);
for i = 1:m
h = sigmoid(X(i,:) * theta);
if h >= 0.5
p(i) = 1;
end
end
end
別の方法:loopを使わずに一括計算するとこうなります
p = round(sigmoid(X*theta));
round
関数は0.5以上の時は1になり、0.5未満の時は0になります。
実行結果:
Train Accuracy: 89.000000
問題2
2つのテストからマイクロチップの質量を判定するプログラムです。 学習データは以下です(y=0はNG、y=1はOK)。
フィーチャ
6次フィーチャを想定します
mapFeature(x) = \left[
\begin{array}{c}
1 \\
x_ 1 \\
x_ 2 \\
x_ 1^2 \\
x_ 1x_ 2 \\
x_ 2^2 \\
x_ 1^3 \\
... \\
x_ 1x_ 2^5 \\
x_ 2^6
\end{array}
\right]
Cost function and gradient
- Cost function
$$ J(\theta) = \frac{1}{m}\sum_ {i=1}^{m}[-y^{(i)}\log(h_ \theta(x^{(i)}))-(1-y^{(i)})\log(1-h_ \theta(x^{(i)}))] + \frac{\lambda}{2m}\sum_ {j=1}^{n}\theta_ j^2 $$
- Gradient
$j=0$のとき
$$ \frac{\partial J(\theta)}{\partial \theta_ j} = \frac{1}{m}\sum_ {i=1}^m (h_ \theta(x^{(i)})-y^{(i)})x_ j^{(i)} $$
$j\ge1$のとき
$$ \frac{\partial J(\theta)}{\partial \theta_ j} = \frac{1}{m}\sum_ {i=1}^m (h_ \theta(x^{(i)})-y^{(i)})x_ j^{(i)} +\frac{\lambda}{m}\theta_ j $$
注意したいのは正規化のパラメータは0からではなく、1からです。Octaveで書くと2からになります。
$\sum_ {j=1}^{n}\theta_ j^2$はloopで計算するのもいいですが、よく見たら$\theta$ベクトル($\theta_ 0$を除き)のノルムの2乗です。Octaveはnorm
関数があるので、実装に便利です。
実装:
function [J, grad] = costFunctionReg(theta, X, y, lambda)
m = length(y); % number of training examples
J = 0;
grad = zeros(size(theta));
% Cost function
for i = 1:m
h = sigmoid(X(i,:) * theta);
J += -y(i)*log(h) - (1 - y(i))*log(1-h);
end
J = J / m + norm(theta(2:size(theta)))^2 * lambda / (2*m);
% Gradient
for j = 1:size(theta)
for i = 1:m
h = sigmoid(X(i,:) * theta);
grad(j) += (h - y(i)) * X(i,j);
end
if j > 1
grad(j) += lambda * theta(j);
end
end
grad = grad / m;
end
番外編:Gradientのベクトル化バージョン
$j=0$と$j\ge1$を分けて計算します。
実装:
n = size(theta);
s = (sigmoid(X * theta) - y) / m;
grad(1) = X(:,1)' * s;
grad(2:n) = X(:,2:n)' * s + lambda * theta(2:n) / m;
結果
問題1と同じくfminunc
を使って結果は以下になります。
Train Accuracy: 83.050847