Logistic回归
Logistic 回归虽然名字叫回归,但是它是用来做分类的。其主要思想是: 根据现有数据对分类边界线建立回归公式,以此进行分类。假设现在有一些数据点,我们用一条直线对这些点进行拟合(这条直线称为最佳拟合直线),这个拟合的过程就叫做回归。
Sigmoid 函数
Sigmoid 函数具体的计算公式
def sigmoid(inX):
return 1.0/(1+exp(-inX))
为了实现 Logistic 回归分类器,我们可以在每个特征上都乘以一个回归系数(如下公式所示),然后把所有结果值相加,将这个总和代入 Sigmoid 函数中,进而得到一个范围在 0~1 之间的数值。任何大于 0.5 的数据被分入 1 类,小于 0.5 即被归入 0 类。所以, Logistic 回归也可以被看成是一种概率估计。
Sigmoid 函数的输入记为 z ,由下面公式得到:
逻辑斯蒂回归模型
1. 二项逻辑斯蒂回归模型
二项逻辑斯蒂回归模型是如下的条件概率分布:
意义:在逻辑斯蒂回归模型中,输出Y=1的对数几率是输入x的线性函数。或者说,输出Y=1的对数几率是由属于x的线性函数表示的模型,即逻辑斯蒂回归模型。
感知机只通过决策函数(w⋅x)的符号来判断属于哪一类。逻辑斯蒂回归需要再进一步,它要找到分类概率P(Y=1)与输入向量x的直接关系,再通过比较概率值来判断类别。
令决策函数(w⋅x)输出值等于概率值比值取对数,即:
逻辑斯蒂回归模型的定义式P(Y=1|x)中可以将线性函数w⋅x转换为概率,这时,线性函数的值越接近正无穷,概率值就越接近1;线性函数的值越接近负无穷,概率值就接近0.
2. 模型参数估计
应用极大似然法进行参数估计,从而获得逻辑斯蒂回归模型。
上式连乘符号内的两项中,每个样本都只会取到两项中的某一项。若该样本的实际标签yi=1,取样本计算为1的概率值π(xi);若该样本的实际标签yi=0,取样本计算的为0的概率值1−π(xi)。
3对数似然函数为:
对上式中的L(w)求极大值,得到w的估计值。
问题转化成以对数似然函数为目标函数的无约束最优化问题,通常采用梯度下降法以及拟牛顿法求解w。
假设w的极大估计值是wˆ,那么学到的逻辑斯蒂回归模型为:
利用梯度上升找到最佳参数
4. 交叉熵损失函数的求导:逻辑回归的另一种理解是以交叉熵作为损失函数的目标最优化。交叉熵损失函数可以从上文最大似然推导出来。 交叉熵损失函数为:
则可以得到目标函数为:
计算J(θ)对第j个参数分量θj求偏导:
def gradAscent(dataMatIn, classLabels):
'''正常的梯度上升法
:param dataMatIn: ataMatIn 是一个2维NumPy数组,每列分别代表每个不同的特征,每行则代表每个训练样本。
:param classLabels: classLabels 是类别标签,它是一个 1*100 的行向量。为了便于矩阵计算,需要将该行向量转换为列向量,做法是将原向量转置,再将它赋值给labelMat。
:return array(weights)-得到的最佳回归系数
'''
dataMatrix = mat(dataMatIn)
labelMat = mat(classLabels).transpose() # 转化为矩阵[[0,1,0,1,0,1.....]],并转制[[0],[1],[0].....]
m,n = shape(dataMatrix)
alpha = 0.001 # alpha代表向目标移动的步长
maxCycles = 500 # 迭代次数
weights = ones((n,1)) # 生成一个长度和特征数相同的矩阵
for k in range(maxCycles):
h = sigmoid(dataMatrix*weights) # mxn+nx1->mx1
error = (labelMat - h)
weights = weights + alpha * dataMatrix.transpose() * error # 矩阵乘法,最后得到回归系数
return array(weights)
梯度上升优化算法在每次更新数据集时都需要遍历整个数据集,计算复杂都较高;改进方法为随机梯度上升:一次只用一个样本点来更新回归系数。
def stocGradAscent0(dataMatrix, classLabels):
m,n = shape(dataMatrix); alpha = 0.01
weights = ones(n)
for i in range(m):
h = sigmoid(sum(dataMatrix[i]*weights))
error = classLabels[i] - h
print weights, "*"*10 , dataMatrix[i], "*"*10 , error
weights = weights + alpha * error * dataMatrix[i]
return weights
改进的随机梯度上升算法:1,alpha在每次迭代的时候都会调整;2,通过随机选取样本来更新回归系数;
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
'''
:param dataMatrix: 输入数据的数据特征(除去最后一列数据)
:param classLabels: 输入数据的类别标签(最后一列数据)
:param numIter: 迭代次数
:return: weights -- 得到的最佳回归系数
'''
m,n = shape(dataMatrix)
weights = ones(n) # 创建与列数相同的矩阵的系数矩阵,所有的元素都是1
for j in range(numIter): # 随机梯度, 循环150,观察是否收敛
dataIndex = range(m)
for i in range(m):
alpha = 4/(1.0+j+i)+0.0001 # alpha 会随着迭代不断减小,但永远不会减小到0,因为后边还有一个常数项0.0001
randIndex = int(random.uniform(0,len(dataIndex))) # random.uniform(x, y) 方法将随机生成下一个实数,它在[x,y]范围内,x是这个范围内的最小值,y是这个范围内的最大值。
h = sigmoid(sum(dataMatrix[randIndex]*weights)) # sum(dataMatrix[i]*weights)为了求 f(x)的值, f(x)=a1*x1+b2*x2+..+nn*xn
error = classLabels[randIndex] - h
weights = weights + alpha * error * dataMatrix[randIndex]
del(dataIndex[randIndex])
return weights
根据权重用logistic画最佳拟合直线
def plotBestFit(dataArr, labelMat, weights):
'''将我们得到的数据可视化展示出来
:param dataArr: 样本数据的特征
:param labelMat: 样本数据的类别标签,即目标变量
:param weights: 回归系数
:return:
'''
n = shape(dataArr)[0]
xcord1 = []; ycord1 = []
xcord2 = []; ycord2 = []
for i in range(n):
if int(labelMat[i])== 1:
xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])
else:
xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2])
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
ax.scatter(xcord2, ycord2, s=30, c='green')
x = arange(-3.0, 3.0, 0.1)
y = (-weights[0]-weights[1]*x)/weights[2]
ax.plot(x, y)
plt.xlabel('X'); plt.ylabel('Y')
plt.show()