Logistic Regression Classifier逻辑回归主要思想就是用最大似然概率方法构建出方程,为最大化方程,利用牛顿梯度上升求解方程参数。
优点:计算代价不高,易于理解和实现。
缺点:容易欠拟合,分类精度可能不高。
使用数据类型:数值型和标称型数据。
介绍逻辑回归之前,我们先看一问题,有个黑箱,里面有白球和黑球,如何判断它们的比例。
我们从里面抓3个球,2个黑球,1个白球。这时候,有人就直接得出了黑球67%,白球占比33%。这个时候,其实这个人使用了最大似然概率的思想,通俗来讲,当黑球是67%的占比的时候,我们抓3个球,出现2黑1白的概率最大。我们直接用公式来说明。
假设黑球占比为P,白球为1-P。于是我们要求解MAX(PP(1-P)),显而易见P=67%(求解方法:对方程求导,使导数为0的P值即为最优解)
我们看逻辑回归,解决的是二分类问题,是不是和上面黑球白球问题很像,是的,逻辑回归也是最大似然概率来求解。
假设我们有n个独立的训练样本{(x1, y1) ,(x2, y2),…, (xn, yn)},y={0, 1}。那每一个观察到的样本(xi, yi)出现的概率是:
上面为什么是这样呢?当y=1的时候,后面那一项是不是没有了,那就只剩下x属于1类的概率,当y=0的时候,第一项是不是没有了,那就只剩下后面那个x属于0的概率(1减去x属于1的概率)。所以不管y是0还是1,上面得到的数,都是(x, y)出现的概率。那我们的整个样本集,也就是n个独立的样本出现的似然函数为(因为每个样本都是独立的,所以n个样本出现的概率就是他们各自出现的概率相乘):
这里我们稍微变换下L(θ):取自然对数,然后化简(不要看到一堆公式就害怕哦,很简单的哦,只需要耐心一点点,自己动手推推就知道了。注:有xi的时候,表示它是第i个样本,下面没有做区分了,相信你的眼睛是雪亮的),得到:
其中第三步到第四步使用了下面替换。
这时候为求最大值,对L(θ)对θ求导,得到:
然后我们令该导数为0,即可求出最优解。但是这个方程是无法解析求解(这里就不证明了)。
最后问题变成了,求解参数使方程L最大化,求解参数的方法梯度上升法(原理这里不解释了,看详细的代码的计算方式应该更容易理解些)。
根据这个转换公式
我们代入参数和特征,求P,也就是发生1的概率。
上面这个也就是常提及的sigmoid函数,俗称激活函数,最后用于分类(若P(y=1|x;Θ\ThetaΘ )大于0.5,则判定为1)。
下面是详细的逻辑回归代码,代码比较简单,主要是要理解上面的算法思想。个人建议,可以结合代码看一步一步怎么算的,然后对比上面推导公式,可以让人更加容易理解,并加深印象。
from numpy import *
filename='...\\testSet.txt' #文件目录
def loadDataSet(): #读取数据(这里只有两个特征)
dataMat = []
labelMat = []
fr = open(filename)
for line in fr.readlines():
lineArr = line.strip().split()
dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])]) #前面的1,表示方程的常量。比如两个特征X1,X2,共需要三个参数,W1+W2*X1+W3*X2
labelMat.append(int(lineArr[2]))
return dataMat,labelMat
def sigmoid(inX): #sigmoid函数
return 1.0/(1+exp(-inX))
def gradAscent(dataMat, labelMat): #梯度上升求最优参数
dataMatrix=mat(dataMat) #将读取的数据转换为矩阵
classLabels=mat(labelMat).transpose() #将读取的数据转换为矩阵
m,n = shape(dataMatrix)
alpha = 0.001 #设置梯度的阀值,该值越大梯度上升幅度越大
maxCycles = 500 #设置迭代的次数,一般看实际数据进行设定,有些可能200次就够了
weights = ones((n,1)) #设置初始的参数,并都赋默认值为1。注意这里权重以矩阵形式表示三个参数。
for k in range(maxCycles):
h = sigmoid(dataMatrix*weights)
error = (classLabels - h) #求导后差值
weights = weights + alpha * dataMatrix.transpose()* error #迭代更新权重
return weights
def stocGradAscent0(dataMat, labelMat): #随机梯度上升,当数据量比较大时,每次迭代都选择全量数据进行计算,计算量会非常大。所以采用每次迭代中一次只选择其中的一行数据进行更新权重。
dataMatrix=mat(dataMat)
classLabels=labelMat
m,n=shape(dataMatrix)
alpha=0.01
maxCycles = 500
weights=ones((n,1))
for k in range(maxCycles):
for i in range(m): #遍历计算每一行
h = sigmoid(sum(dataMatrix[i] * weights))
error = classLabels[i] - h
weights = weights + alpha * error * dataMatrix[i].transpose()
return weights
def stocGradAscent1(dataMat, labelMat): #改进版随机梯度上升,在每次迭代中随机选择样本来更新权重,并且随迭代次数增加,权重变化越小。
dataMatrix=mat(dataMat)
classLabels=labelMat
m,n=shape(dataMatrix)
weights=ones((n,1))
maxCycles=500
for j in range(maxCycles): #迭代
dataIndex=[i for i in range(m)]
for i in range(m): #随机遍历每一行
alpha=4/(1+j+i)+0.0001 #随迭代次数增加,权重变化越小。
randIndex=int(random.uniform(0,len(dataIndex))) #随机抽样
h=sigmoid(sum(dataMatrix[randIndex]*weights))
error=classLabels[randIndex]-h
weights=weights+alpha*error*dataMatrix[randIndex].transpose()
del(dataIndex[randIndex]) #去除已经抽取的样本
return weights
def plotBestFit(weights): #画出最终分类的图
import matplotlib.pyplot as plt
dataMat,labelMat=loadDataSet()
dataArr = array(dataMat)
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('X1')
plt.ylabel('X2')
plt.show()
def main():
dataMat, labelMat = loadDataSet()
weights=gradAscent(dataMat, labelMat).getA()
plotBestFit(weights)
if __name__=='__main__':
main()
跑完代码结果:
当然,还可以换随机梯度上升和改进的随机梯度上升算法试试,效果都还不错。
下面是代码使用的数据,可以直接复制本地text里面,跑上面代码。
-0.01761214.0530640
-1.3956344.6625411
-0.7521576.5386200
-1.3223717.1528530
0.42336311.0546770
0.4067047.0673351
0.66739412.7414520
-2.4601506.8668051
0.5694119.5487550
-0.02663210.4277430
0.8504336.9203341
1.34718313.1755000
1.1768133.1670201
-1.7818719.0979530
-0.5666065.7490031
0.9316351.5895051
-0.0242056.1518231
-0.0364532.6909881
-0.1969490.4441651
1.0144595.7543991
1.9852983.2306191
-1.693453-0.5575401
-0.57652511.7789220
-0.346811-1.6787301
-2.1244842.6724711
1.2179169.5970150
-0.7339289.0986870
-3.642001-1.6180871
0.3159853.5239531
1.4166149.6192320
-0.3863233.9892861
0.5569218.2949841
1.22486311.5873600
-1.347803-2.4060511
1.1966044.9518511
0.2752219.5436470
0.4705759.3324880
-1.8895679.5426620
-1.52789312.1505790
-1.18524711.3093180
-0.4456783.2973031
1.0422226.1051551
-0.61878710.3209860
1.1520830.5484671
0.8285342.6760451
-1.23772810.5490330
-0.683565-2.1661251
0.2294565.9219381
-0.95988511.5553360
0.49291110.9933240
0.1849928.7214880
-0.35571510.3259760
-0.3978228.0583970
0.82483913.7303430
1.5072785.0278661
0.0996716.8358391
-0.34400810.7174850
1.7859287.7186451
-0.91880111.5602170
-0.3640094.7473001
-0.8417224.1190831
0.4904261.9605391
-0.0071949.0757920
0.35610712.4478630
0.34257812.2811620
-0.810823-1.4660181
2.5307776.4768011
1.29668311.6075590
0.47548712.0400350
-0.78327711.0097250
0.07479811.0236500
-1.3374720.4683391
-0.10278113.7636510
-0.1473242.8748461
0.5183899.8870350
1.0153997.5718820
-1.658086-0.0272551
1.3199442.1712281
2.0562165.0199811
-0.8516334.3756911
-1.5100476.0619920
-1.076637-3.1818881
1.82109610.2839900
3.0101508.4017661
-1.0994581.6882741
-0.834872-1.7338691
-0.8466373.8490751
1.40010212.6287810
1.7528425.4681661
0.0785570.0597361
0.089392-0.7153001
1.82566212.6938080
0.1974459.7446380
0.1261170.9223111
-0.6797971.2205301
0.6779832.5566661
0.76134910.6938620
-2.1687910.1436321
1.3886109.3419970
0.31702914.7390250
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。
本文标题: python代码实现逻辑回归logistic原理
本文地址: http://www.cppcns.com/jiaoben/python/267639.html