概念:
分类算法是一种典型的监督学习算法,数据标签为离散值,比如{0,1},而我们所要做的任务就是通过数据集的训练,让算法能够预测下一组数据为另外一个值的概率。
步骤:
前面的gradient descent 介绍了我们的一般方法,我们继续以此步骤完成我们的二分类算法。
在此之前,我们需要将数据集进行分类,例如:有和没有等等对立的元素用{0,1}来表征,这里就需要引入阈值函数,sigmoid
f
(
x
)
=
1
1
+
e
−
x
f(x) = \frac{1}{1+e^{-x}}
f(x)=1+e−x1
它的函数图像如下:
它在0和一之间的变化趋势很大,同时值域在[0,1],因此可以很好的区分样本。
画出图像曲线:
加载数据:
data = np.loadtxt('ex2data1.txt', delimiter=',')
X = data[:, 0:2]
y = data[:, 2]
首先根据数据集编写代码画出它的函数图像:
# plot data
def plotData(X, y):
X_1 = X[y == 1]
X_0 = X[y == 0]
plt.plot(X_1[:, 0], X_1[:, 1], 'k+')
plt.plot(X_0[:, 0], X_0[:, 1], 'yo')
plt.legend(['Admitted', 'Not admitted'])
输出结果如下:
由上图可以有一个边界将两个样本分割成两个不同的部分,而我们接下来的任务就是将这条曲线给求出来,并通过它预测下一组数组的label。
求出分割近似曲线:
同上篇文一般,我们需要先求出它的cost function,只是与线性回归不同,此次我们求的曲线如下:
f
(
x
)
=
1
1
+
e
−
θ
T
x
f(x) = \frac{1}{1+e^{-\theta^Tx}}
f(x)=1+e−θTx1
可以看出它是一种非线性的表达,其中的
θ
T
\theta^{T}
θT代表着权重矩阵的转置,同样x也是一个特征向量的矩阵,此时的损失函数自然不可以像线性回归一样,直接通过标签的值进行相减,因为那样计算出来的值是相当复杂的,同时它也是一个非凸函数,会有很多的局部最优解,此时我们可以使用log函数将它进行凸函数化,所以,新的损失函数如下:
C
o
s
t
(
h
θ
(
x
)
,
y
)
=
{
−
l
o
g
(
h
θ
(
x
)
)
i
f
y
=
1
−
l
o
g
(
1
−
h
θ
(
x
)
)
i
f
y
=
0
Cost(h_\theta(x),y) = \begin{cases}-log(h_\theta(x))&ify=1 \\-log(1-h_\theta(x))&ify=0\end{cases}
Cost(hθ(x),y)={−log(hθ(x))−log(1−hθ(x))ify=1ify=0
J ( θ ) = − 1 m ∑ C o s t ( h θ ( x ) , y ) J(\theta) = -\frac{1}{m}\sum Cost(h_\theta(x), y) J(θ)=−m1∑Cost(hθ(x),y)
我们来解释一下这个损失函数的含义,我们已经知道 h θ ( x ) h_\theta(x) hθ(x)的值域在[0,1]之间(见上面的函数图像),那么根据log函数的函数图像:
注意我们这边的log函数其实是ln函数
参照函数图像可知,当我们的定义域,亦即 h θ ( x ) h_\theta(x) hθ(x)的值不断趋向于1时,它的值的变化程度变缓,也就是说得出来的情况越好,那么我们的损失值越小。这十分符合我们对损失函数的定义。下式亦然。
但是上式其实可以整合成一个式子,如下:
C
o
s
t
(
h
θ
(
x
)
,
y
)
=
y
i
l
o
g
(
h
θ
(
x
i
)
)
+
(
1
−
y
i
)
(
1
−
l
o
g
(
1
−
h
θ
(
x
i
)
)
)
Cost(h_\theta(x),y) = y^{i}log(h_\theta(x^{i})) + (1-y^{i})(1-log(1-h_\theta(x^{i})))
Cost(hθ(x),y)=yilog(hθ(xi))+(1−yi)(1−log(1−hθ(xi)))
J ( θ ) = − 1 m ∑ C o s t ( h θ ( x ) , y ) J(\theta) = -\frac{1}{m}\sum Cost(h_\theta(x), y) J(θ)=−m1∑Cost(hθ(x),y)
上下两种形式都是等价的,可自行推导。
梯度下降求出权重矩阵:
首先编写出sigmoid函数:
def sigmoid(z):
return 1 / (1 + np.exp(-z))
其中的theta需要每次进行更新,最后得到一个最符号结果的向量集,而更新的依据就是损失函数,costfunction
def costFunction(initial_theta, X, y):
J = 0
grad = np.zeros(np.size(initial_theta, ))
z = X.dot(initial_theta)
J = 1 / m * (-y.dot(np.log(sigmoid(z))) - ((1 - y).dot(np.log(1 - sigmoid(z)))))
grad = 1 / m * (X.T.dot(sigmoid(z) - y))
return J, grad
由于普通的梯度下降可能需要运行很多次,所以我们直接调用函数库来实现快速收敛(与matlab代码有差异)
result = op.minimize(fun=costFunction, x0=initial_theta, args=(X, Y), method='TNC', jac=gradient)
很快的得到权重矩阵:
通过矩阵我们就可以绘制边界了:
绘制边界:
def plotDecisionBoundary(theta, x, y):
pos = np.where(y == 1)
neg = np.where(y == 0)
p1 = plt.scatter(x[pos, 1], x[pos, 2], marker='+', s=60, color='r')
p2 = plt.scatter(x[neg, 1], x[neg, 2], marker='o', s=60, color='y')
plot_x = np.array([np.min(x[:, 1])-2, np.max(x[:, 1]+2)])
plot_y = -1/theta[2]*(theta[1]*plot_x+theta[0])
plt.plot(plot_x, plot_y)
plt.legend((p1, p2), ('Admitted', 'Not admitted'), loc='upper right', fontsize=8)
plt.xlabel('Exam 1 score')
plt.ylabel('Exam 2 score')
plt.show()
预测与正确率:
def predict(theta, x):
return np.round(sigmoid(x.dot(theta)))
print('Train Accuracy: %f', np.mean(np.double(p == y)) * 100)
参考文档:
全部代码:
部分代码参考:
ning/blob/wrong/Logistic%20Regression/Logistic%20Regression-reset.py)
部分代码参考: