机器学习笔记(2): Logistic 回归
Logistic 回归是线性回归中一个很重要的部分。
Logistic 函数:
其中:
- \(L\) 表示最大值
- \(x_0\) 表示对称中心
- \(k\) 表示倾斜度
一般来说,都将 \(L\) 设为 \(1\),而 \(k\) 和 \(x_0\) 在参数中控制。
认为特征只有一个,那么自然:
认为 \(\vec x\) 是特征向量,并且是增广向量,也就是:
认为参数向量也是增广的:
那么:
对于多组数据,\(X = \begin{bmatrix} \vec x_0 \\ \vec x_1 \\ \ldots \\ \vec x_m \end{bmatrix}\):
注意最终得到是一个向量,\(\sigma\) 函数作用于向量中的每个单独的元素。
利用交叉熵作为损失函数:
其中 \(\hat y\) 表示预测分类,而 \(y\) 表示实际分类。
由于 \(\sigma'(x) = \sigma(x)(1 - \sigma(x))\),自然的可以推出其偏导数:
写成向量形式也就是:
于是利用梯度下降算法:
代码和梯度下降函数十分相似。
Feature Mapping
合理的利用线性回归可以解决很多复杂的问题。
大概率我们需要一个类似于圆的东西才可以拟合。
考虑到在高中我们学过:
可以表示一个圆,那么我们就可以利用重映射:
的方式将特征向量进行一点点简单的变换,那么自然就变成了对于多个参数的线性回归问题,一种可能的拟合是:
当然,我们也可以更复杂的利用这些参数,例如 \(x^3\),\(\sqrt x\),\(\frac 1 x\) 之类的参数,这取决于我们想要如何去拟合。
正则化参数
和平方损失函数的正则化方式一模一样,见 机器学习笔记(1): 梯度下降算法
代码
function g = sigmoid(z)
g = 1.0 ./ (1.0 + exp(-z));
end
function [J, grad] = costFunctionReg(theta, X, y, lambda)
m = length(y);
H = sigmoid(X * theta);
temp = theta;
temp(1) = 0;
J = 1 / m * (- y' * log(H) - (1 - y)' * log(1 - H)) + temp' * temp * lambda / 2 / m;
grad = 1 / m * (X' * (H - y)) + lambda / m * temp;
end
function theta = train(X, y, lambda)
initial_theta = zeros(size(X, 2), 1);
options = optimset('GradObj', 'on', 'MaxIter', 400);
[theta, J, exit_flag] = ...
fminunc(@(t)(costFunctionReg(t, X, y, lambda)), initial_theta, options);
end
function p = predict(theta, X)
m = size(X, 1);
H = sigmoid([ones(m, 1) X] * theta);
p = H >= 0.5;
end
其实整体的代码都非常的简单并且简洁。
Softmax Regression
其实就是多分类的 Logistic 回归:
其中 \(C\) 表示分类数,而 \(W = \begin{bmatrix} \omega_1 & \omega_2 & \ldots & \omega_C \end{bmatrix}\),其中 \(\omega_i\) 就表示某一个 Logistic 函数的参数。
由于其实就是多个 Logistic 函数,所以其偏导数和参数学习过程非常相似:
值得注意的是,对于每一个 \(\omega_i\) 减去同一个 \(\theta\) 结果不会改变,意味着一般都需要正则化。
One VS All Classifier
其实就是多次 Logistic 回归。
function [J, grad] = lrCostFunction(theta, X, y, lambda)
m = length(y);
H = sigmoid(X * theta);
temp = theta;
temp(1) = 0;
J = 1 / m * (- y' * log(H) - (1 - y)' * log(1 - H)) + temp' * temp * lambda / 2 / m;
grad = 1 / m * (X' * (H - y)) + lambda / m * temp;
end
function [all_theta] = oneVsAll(X, y, num_labels, lambda)
m = size(X, 1);
n = size(X, 2);
all_theta = zeros(n + 1, num_labels);
X = [ones(m, 1) X];
options = optimset('GradObj', 'on', 'MaxIter', 300);
for c = 1:num_labels
initial_theta = zeros(n + 1, 1);
[theta] = ...
fmincg(@(t)(lrCostFunction(t, X, (y == c), lambda)), ...
initial_theta, options);
all_theta(:, c) = theta;
end
end
function p = predictOneVsAll(all_theta, X)
m = size(X, 1);
X = [ones(m, 1) X];
H = X * all_theta;
[_, p] = max(H, [], 2);
end
也就是对于每一个分类来一次线性回归而已,并没有什么特别之处。