一 .基于Logistic回归函数和Sigmoid函数的分类
在讨论Logistic函数前,我们不妨先来了解几个概念:
1.事件的几率:它是指某事件发生的概率和该事件不发生的概率的比值.无妨设事件发生的概率为p,那么显然 事件的几率 :
?
我们将该几率取对数,即可得到其对数几率:
?
我们想要的函数应该是,接受输入的特征,然后输出预测的类别,例如处理二分类问题,我们应该得到0或者1(你是不是想起了海维塞德阶跃函数???),然而此处我们并用不到它(因为其在跳跃点上瞬间从0跳跃到1),所以我们要寻求更好的选择:
我们把输入特征x时,分类为1的概率线性表示:
?
经过简单的取反运算我们就得到了Sigmoid函数:
其图像如图所示:
? 图1
当x=0时,Sigmoid函数的值为0.5,随着x的无限增大,函数值将逼近1,随着x的无限减小,函数值将无限逼近于0.
当横坐标足够大的时候,我们就可以将Sigmoid函数视为一个单位阶跃函数(如图1下).
那么问题来了,如何实现将横坐标放大呢? 那当然就是在每个特征上乘以一个系数(将之称为回归系数),然后将所有结果相加,将结果作为Sigmoid函数的输入,如此我们就得到了一个在(0,1)之间的输出结果.我们将大于0.5的数据归为1类,小于0.5的数据归为0类,这样就达到了分类的目的.
现在我们已经确定了分类函数,是不是就意味着我们可以进行分类了呢?
其实不然,事实上我们还没有确定最佳的回归系数
*二.最优化方法确定最佳回归系数
Sigmoid函数的输入记为 z
其中向量 X 是分类器的输入数据,w为我们所寻求的最佳回归系数
1.梯度上升法
(1).基本思想:要找到某个函数的最大值,我们只需要沿着函数的梯度方向移动,并循环迭代直到满足条件.(事实上这对函数有一定要求——在待计算的点,函数必须有定义且可微。
我们将梯度记 ? ,则函数f(x,y)的梯度如下表示:
这样每次沿 x 方向移动 ,沿 y 方向移动 .
梯度上升法的迭代公式如下:
?
下图为一个实例:
三.通过梯度上升法获取最佳回归系数
def loadDataSet(path):
dataMat=[];labelMat=[]
fr=open(path)
for line in fr.readlines():
lineArr=line.strip().split()
dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])])
labelMat.append(int(lineArr[2]))
return dataMat,labelMat
Sigmoid函数
def sigmoid(inX):
return 1.0/(1.0+np.exp(-inX))
def gradAscent(dataMat,classLebels):
dataMatrix=np.mat(dataMat)
labelMat=np.mat(classLebels).transpose()
m,n=np.shape(dataMatrix)
alpha=0.001
maxCycles=500
weights=np.ones((n,1))
for k in range(maxCycles):
h=sigmoid(dataMatrix*weights)
error=(labelMat-h)
weights=weights+alpha*dataMatrix.transpose()*error
return weights
下面我们进行可视化并画出决策边界:
def plotBestFit(wei):
path='D:/python 代码/机器学习/logistic/testSet.txt'
weights=np.array(wei)
dataMat,labelMat=loadDataSet(path)
dataArr=np.array(dataMat)
n=np.shape(dataArr)[0]
xcord1=[];ycoord1=[]
xcord2=[];ycoord2=[]
for i in range(n):
if int(labelMat[i])==1:
xcord1.append(dataArr[i,1]);ycoord1.append(dataArr[i,2])
else:
xcord2.append(dataArr[i,1]);ycoord2.append(dataArr[i,2])
fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(xcord1,ycoord1,s=30,c='red',marker='s')
ax.scatter(xcord2,ycoord2,s=30,c='green')
x=np.arange(-3.0,3.0,0.1)
y=(-weights[0]-weights[1]*x)/weights[2]
ax.plot(x,y)
plt.xlabel('x1');plt.ylabel('x2')
plt.show()
得到结果如下图所示:
事实上分类效果还是不错的,但我们还需要注意该拟合函数是如何确定的呢?
x=np.arange(-3.0,3.0,0.1)
y=(-weights[0]-weights[1]*x)/weights[2]
对于这一步:事实上我们将Sigmoid函数设置为0,上面已经提到0是该二分类的的分界线,即
?由此即可得到x1,x2的关系式
观察代码,我们可以发现每次更新回归系数时,都需要遍历整个数据集,时间复杂度是极高的,在处理成千上万的数据时,计算的复杂度非常之高,我们可以通过下面的随机梯度上升法来训练.
def stocGradAscent(dataMatrix,classLebels,numIter=150):
m,n=np.shape(dataMatrix)
alpha=0.01
weights=ones(n)
for j in range(numIter):
dataIndex=list(range(m))
for i in range(m):
alpha=4/(1.0+i+j)+0.01
randIndex=int(np.random.uniform(0,len(dataIndex)))
h=sigmoid(sum(dataMatrix[randIndex]*weights))
error=classLebels[randIndex]-h
weights=weights+alpha*error*dataMatrix[randIndex]
del(dataIndex[randIndex])
return weights
有兴趣的小伙伴可以对比学习一下二者的区别(笔者太懒)
以上是迭代了500次的结果,与梯度上升法的结果差不多,但却大大的降低了时间复杂度
四.分类器的构建(以疝气病症预测病马的死亡率为例)
def classfifyVector(inX,weights):
prob=sigmoid(sum(inX*weights))
if prob>0.5:
return 1.0
else:
return 0.0
def colicTest():
frTrain=open('D:\python 代码\机器学习\logistic\horseColicTraining.txt')
frTest=open('D:\python 代码\机器学习\logistic\horseColicTest.txt')
trainingSet=[];trainingLabels=[]
for line in frTrain.readlines():
currLine=line.strip().split()
lineArr=[]
for i in range(21):
lineArr.append(float(currLine[i]))
trainingSet.append(lineArr)
trainingLabels.append(float(currLine[21]))
traingWeights=stocGradAscent(np.array(trainingSet),trainingLabels,500)
errorCount=0;numTestVec=0.0
for line in frTest.readlines():
numTestVec+=1.0
currLine=line.strip().split('\t')
lineArr=[]
for i in range(21):
lineArr.append(float(currLine[i]))
if int(classfifyVector(np.array(lineArr),traingWeights))!=int(currLine[21]):
errorCount+=1.0
errorRate=(float(errorCount)/numTestVec)
print('错误率为: %f%%' % (errorRate*100))
return errorRate
def multiTest():
numTests=10;errorSum=0.0
for k in range(numTests):
errorSum+=colicTest()
print('经过 %d 次迭代后,平均错误率为: %f%%' %(numTests,(errorSum/float(numTests)*100)))
结果如下:
错误率为: 43.283582% 错误率为: 35.820896% 错误率为: 37.313433% 错误率为: 25.373134% 错误率为: 25.373134% 错误率为: 35.820896% 错误率为: 31.343284% 错误率为: 43.283582% 错误率为: 37.313433% 错误率为: 43.283582% 经过 10 次迭代后,平均错误率为: 35.820896%
坑外话:由于笔者水平太浅,如有错误敬请提出 参考书籍: PeterHarrington《机器学习实战》 Dimitri P.Bertsekas《概率导论》 李航 《统计学习方法》
数据集可到本人git上下载.地址:https://github.com/lei324/First-Repository
|