Logistic回归属于对数线性模型,是统计学习中的经典分类方法。
二项Logistic回归的模型如下:
(1)
考虑对输入实例x进行分类的线性函数的值,当趋近于正无穷时,概率值趋近于1,当趋近于负无穷时,概率值趋近于0。
模型参数估计(极大似然法估计参数):
假设函数:
似然函数为:
之前用过的损失函数是均方误差函数,L(y,y1) = 1/2(y-y1)^2,但是当参数数目多于一个时,通过梯度下降法可能会出现多个局部最优值,而导致无法得到最优解,因此逻辑回归损失函数采用对数似然函数。
对数似然函数为:
带入(1) 可得
目标函数的自变量是权重向量w,最小化目标函数就等价于最大化似然估计,对w求导:
例子:
假设我们要对二维平面的点作分类,则输入的特征为x1,x2(或者说是x,y)。参数设置两个分别是w1、w2,在加上一个biase b,这样我们得到一个函数值 z = w1x1 +w2x2 +b,采用向量化的方式,改写为 z=w^Tx,其中将b看作w0x0 且 x0=1。向量x
是分类器的输入实例,向量w是需要求得的最佳参数。
对上面说到的目标函数求梯度:
在学习机器学习实战中,老师用b+x系数矩阵的转置乘上误差(真实值与预测值的差值)的积当做结果,而且说了句“此处略去了一个简单的数学推导,我把它留给有兴趣的读者”,此处脑补蒙蔽脸,最不愿意做的就是数学推导,没办法不懂的时候就需要手撕一波。
然后将dataMat.T与误差errors想乘,可以发现和直接求导结果是一样的,所以此处可以直接代替。
线性感知器算法:
使用logisitic函数
import numpy as np
import matplotlib.pyplot as plt
import math
#加载数据集
def loadDataSet(path):
dataMat = []
labelMat = []
fr = open(path)
for line in fr.readlines():
lineArr = line.strip().split(",")
dataMat.append([1,float(lineArr[0]),float(lineArr[1])])
labelMat.append(int(lineArr[2]))
return dataMat,labelMat
#logisitic函数
def Logisitic(inx):
return 1.0/(1+np.exp(-inx))
# 梯度法迭代
def gradAscent(dataMatIn,classLabels):
dataMatrix = np.mat(dataMatIn)
labelMat = np.mat(classLabels).transpose()
m,n = np.shape(dataMatrix)
maxCycle = 500
alpha = 0.001
weights = np.ones((n,1))
for k in range(maxCycle):
h = Logisitic(dataMatrix*weights)
error = labelMat - h
weights = weights+alpha*dataMatrix.T*error
return weights
#绘制散点
def drawScatter(Input,LabelMat):
m,n = np.shape(Input)
print(m,n)
data = np.array(Input)
for i in range(m):
if LabelMat[i] == 1:
plt.scatter(data[i,1],data[i,2],c='blue',marker='o')
else:
plt.scatter(data[i, 1], data[i, 2], c='red', marker='s')
dataArr,labelMat = loadDataSet("testSet.txt")
drawScatter(dataArr,labelMat)
w = gradAscent(dataArr,labelMat)
#绘制拟合曲线
X = np.linspace(-3,3,100)
Y = -(float(w[0])+float(w[1])*X)/float(w[2])
plt.plot(X,Y)
plt.show()
print(w)
用写好的逻辑回归对从疝气病症预测病马的死亡率的数据集进行分类时,效果良好
但是在对之前的一个PLA使用的数据集进行分类时,效果较差:
然后对该数据集的特征数据进行了归一化处理,并且增大了迭代的次数以及减小了学习率,得到了较优的结果:
更改加载数据集代码如下:
def loadDataSet(path):
dataMat = []
labelMat = []
fr = open(path)
for line in fr.readlines():
lineArr = line.strip().split(",")
dataMat.append([float(lineArr[0]),float(lineArr[1])])
labelMat.append(int(lineArr[2]))
# 均值
u = np.mean(dataMat, axis=0)
# 方差
v = np.std(dataMat, axis=0)
dataMat = (dataMat - u) / v
dataSet = [np.insert(a,0,1,axis=0) for a in dataMat]
return dataSet,labelMat
结果如下:
数据集以及源码请查看我的github:https://github.com/feijuan/ML