前言
logistic 回归也是一种简单的分类算法。
主要应用在数据挖掘,模式识别领域。例如死亡率预测,广告点击次数预估,疾病诊断。
优点:可解释性强,速度快
目录
- Logistic 回归
- 算法推导
- 算法流程
- L2 正规化
- 应用例子
一 Logistic 回归(梯度下降法)
1.1 函数定义:
其中
,
n维的列向量
权重向量
这是一个单调递增函数,
正样本概率为>0.5
负样本概率为<0.5
1.2 函数解释:
, 正样本
正样本概率大于负样本概率,则
二 算法推导
2.1 给定训练样本:
为n维特征向量
为类别标签,
定义似然函数,求解极大值:
取对数,等同 求解 对应n重伯努利分布 极小值
:
2.2 为了找到全局最小值,需要证明该函数是凸函数, 证明如下:
因为其中 为离散值, 分两种情况讨论:
2.2.1 对任意某个样本 =0 ,对w
求一阶导数:
二阶导数
其中单个样本的特征向量为:
对于任意向量
所以Hessian矩阵大于0,是凸函数
2.2. 2
求一阶导数
二阶导数为:
也是半正定的矩阵,所以
也是凸函数
合并上面的梯度,使用梯度下降法,求解极小值, 目标函数梯度:
权重更新公式为
三 算法流程
1: 计算当前的损失
2: 更新权重系数向量
3:当前的迭代次数是否大于设置的迭代次数,
,或者梯度小于固定的值(梯度为0,就是全局最小值), 就停止迭代,否则
重复1,2两步
例子中w ,计算结果为
四 L2 正规化(牛顿迭代法)
L2正规化主要为了解决过拟合。
3.1 对数似然函数:
这里, 跟之前的不一样,依然是二分类
可以得到似然函数为:
对数似然函数为:
等同求下面极小值
3.2 正规化问题
该函数是两个凸函数的线性组合,依然是凸函数
Hessian 矩阵为,二阶导数:
>0
则目标函数的梯度:
其中:
Hessian 矩阵为:
其中
D 为对角矩阵,对角元素为:
3.3 牛顿法迭代公式:
其中
证明:
泰勒公式展开损失函数
其中, 是当前的权重系数,为已知值
为下一轮迭代参数,未知值,我们求解的目标是凸函数,那下轮只要一阶导数为0,就可以达到极小值
对 求导:
多维就换成梯度符号,
算法流程:
1: 计算梯度
2: 计算Hessian矩阵
其中D 为对角矩阵,I 单位矩阵(n*n) n为样本维度
3: 计算迭代公式
其中:
前半部分为Hessian 矩阵的逆矩阵
牛顿法最大的问题在于我们必须计算海森矩阵的逆。注意在机器学习应用中,的输入的维度常常与模型参数对应。十万维度的参数并不少见(SVM中文文本分类取词做特征的话,就在十万这个量级),在一些图像识别的场景中,参数可能上十亿。所以,计算海森矩阵或其逆并不现实。对许多函数而言,海森矩阵可能根本无法计算,更不用说表示出来求逆了。
所以,在实际应用中牛顿法很少用于大型的优化问题。但幸运的是,即便我们不求出在
的精确
,而使用一个近似的替代值,上述算法依然有效
缺点:
梯度下降法
收敛速度慢,可能会面临局部极小值
牛顿迭代法
收敛速度快,维度过高时候 Hessian矩阵求逆计算量太大
五 例子:
# -*- coding: utf-8 -*-
"""
Created on Thu Oct 24 14:45:33 2019
@author: chengxf2
"""
import numpy as np
import matplotlib.pyplot as plt
import os
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_breast_cancer
class MyLogistic:
"""
绘制散点
Draw2D
Args
data:
color
return
None
"""
def Draw2D(self, data, color):
m,n = np.shape(data)
x = np.array(data[:,n-2])
y = np.array(data[:,n-1])
plt.scatter(x.flatten(), y.flatten(),c=color, cmap=plt.cm.cool)
plt.xlabel("$z_1$", fontsize=18)
plt.ylabel("$z_2$", fontsize=18)
plt.show()
"""
加载数据集
Args
None
return
Noe
"""
def LoadData(self):
path = os.path.abspath(self.fileName)
fr = open(path)
items = fr.readlines()
trainData =[]
trainLabel =[]
for item in items:
line = item.strip().split()
para = [1.0, float(line[0]), float(line[1])]
trainData.append(para)
trainLabel.append(int(line[2]))
self.m , self.n = np.shape(trainData)
sc = StandardScaler()
data = sc.fit_transform(trainData)
self.trainData = np.mat(data)
self.trainLabel = np.mat(trainLabel).T
self.trainData[:,0]=1.0
print("\n np.shape ", np.shape(self.trainLabel)) ##100,1
"""
使用sigMode 预测
Args
Z: W*X
return
h: 预测值
"""
def Sigmod(self, Z):
a = 1.0/(1+np.exp(-Z))
return a
def __init__(self):
self.m = 0 #样本的个数
self.n = 0 #样本的维度
self.maxIter = 3000
self.minError = 1e-10 ##最低错误率
self.fileName = "testSet.txt"
self.alpha = 0.1
self.LoadData()
self.W = None
"""
训练
Args
None
return
W
"""
def Train(self):
W = np.ones((self.n, 1))
ParaW = []
gradList = []
print("\n self.trainData",self.trainData[0:3])
for it in range(self.maxIter):
Z = self.trainData*W ##(100,1)
A = self.Sigmod(Z) - self.trainLabel ##
##计算当前的梯度
gradient =np.multiply(A, self.trainData)
grad = np.sum(gradient, axis=0)
#print("\n sp " ,grad)
#lossT.append(np.sum(np.abs(loss)))
err = np.linalg.norm(grad)
if err<self.minError:
break
gradList.append(err)
W = W - (grad*self.alpha).T
#W = W - self.trainData.T*loss*self.alpha ##相当于取平均损失,批量梯度
ParaW.append(W)
print("\n self.w: \n",W)
self.W = W
t = np.arange(0,len(gradList),1.0)
plt.figure()
w1 = np.array(ParaW)[:,0].flatten()
w2 = np.array(ParaW)[:,1].flatten()
w3 = np.array(ParaW)[:,2].flatten()
plt.subplot(221)
plt.title("w1")
plt.scatter(t, w1,c='r')
plt.subplot(222)
plt.title("w2")
plt.scatter(t, w2,c='g')
plt.subplot(223)
plt.title("w3")
plt.scatter(t, w3,c='b',s=5)
plt.xlabel("t")
plt.ylabel("w")
plt.subplot(224)
plt.title("loss")
plt.scatter(t, gradList,c='b',s=5)
plt.subplots_adjust(bottom=.1, top=.9, left=.01, right=.99,hspace = 0.5)
plt.show()
def classifyVector(self, X, weights):
Z = X*weights
prob = self.Sigmod(Z)
if prob>0.5:
return int(1)
else:
return int(0)
def Test(self, W):
errorNum = 0
for i in range(self.m):
X = self.trainData[i]
y =self.classifyVector(X, W)
if y != self.trainLabel[i,0]:
print("y ",y, "\t true ",self.trainLabel[i,0])
errorNum +=1
print("\n error: ",errorNum/self.m)
lg = MyLogistic()
lg.Train()
lg.Test(lg.W)