分类与 Logistic 回归
分类用来预测若干个离散值。目前我们仅关注二分分类 (binary classifcation) 即 y 只有两个值 0, 1。0,被称为负类 (negative class); 1 被称为正类 (positive class),或者有时被记为 “-“ 和 “+” , 对于一个训练样本, 给定 , 也被称作为 label 标签。
Logistic 回归就是来预测二分类 0, 1 的一种回归学习算法。Logistic 回归与一般的线性回归主要不同是选择假设函数不一样。
Logistic 回归
改变我们的 hypothesis 形式, , 即 , 被称为 Logistic 函数或 Sigmoid 函数。 Sigmoid 函数有如下的性质:
给出样本的假设函数,怎样才能拟合出 那?尝试用概率知识对参数 进行极大似然估计。
在极大似然估计之前,让我们先写出样本的概率密度函数。固定 , 在给出 时, 的离散概率分布为:
写出样本的联合概率函数:
则有:
求出 的最大值,我们可以使用梯度上升的方法来求得,即先随机初始化下 ,然后利用梯度上升更新规则 来更新 。
我们需要求出 , 让我们假设仅有一个样本的情况,则:
即有更新规则为: 。看起来和我们的 LMS 类似,但是却不是同一个算法。因为现在我们的假设 是一个非线性函数。但是更新规则的相似是巧合吗? 我们将在 GLM 广义线性模型中讨论这个话题。
算法实现
'''
下面是一个仅有两特征的 Logistic Demo
'''
import numpy as np
import matplotlib.pyplot as plt
# 加载数据
def loadDataset(file):
fr = open(file)
dataset = []
labels = []
for line in fr.readlines():
lineNums = line.strip().split()
labels.append(int(lineNums[-1]))
dataset.append([1.0, float(lineNums[0]), float(lineNums[1])])
return dataset, labels
# 计算 Sigmoid hypothesis value
def calcHypothesis(z):
return 1 / (1 + np.exp(-z))
# 批量梯度上升算法
def batchGradientAscend(dataset, labels, maxIter = 500, alpha = 0.001):
dataset = np.mat(dataset)
labels = np.mat(labels).transpose()
m, n = dataset.shape
weights = np.ones((n, 1))
for i in range(maxIter):
error = labels - calcHypothesis(dataset * weights)
weights = weights + alpha * dataset.T * error
return weights
def plotLinear(dataset, labels, weights):
dataset = np.mat(dataset)
labels = np.array(labels)
negLabelsIndices = labels == 0
posLabelsIndices = labels == 1
negLabels = dataset[negLabelsIndices]
posLabels = dataset[posLabelsIndices]
plt.scatter(negLabels[:, 1], negLabels[:, 2], marker='x')
plt.scatter(posLabels[:, 1], posLabels[:, 2], marker='o')
x = np.arange(-3.5, 3.5, 0.1)
y = (-weights[0] - weights[1] * x) / weights[2]
plt.plot(x, np.squeeze(np.asarray(y)))
plt.show()
dataset, labels = loadDataset('./data/testSet.txt')
weights = batchGradientAscend(dataset, labels)
plotLinear(dataset, labels, weights)
运行结果
labels = [1, 0, 1, 0, 1]
amat = np.mat(labels)
arr = np.array(labels)
print(amat, amat.shape)
print(arr, arr.shape)
[[1 0 1 0 1]] (1, 5)
[1 0 1 0 1] (5,)