Fork me on GitHub

机器学习实战(五)Logistic回归

Logistic回归是一种简单的分类算法,提到“回归”,很多人可能觉得与分类没什么关系,Logistic回归通过对数据分类边界的拟合来实现分类。而“回归”也就意味着最佳拟合。要进行最佳拟合,则需要寻找到最佳的拟合参数,一些最优化方法就可以用于最佳回归系数的确定。

Logistic回归

对书中代码做的修改:

  • 1.修改plotBestFit(wei)参数名称plotBestFit(weights)
  • 2.移除plotBestFit()中weights=wei.getA()
  • 3.分析数据画决策边界调用plotBestFit(weights)时传入weights.getA(),其中weight是gredAscent(dataArr,labelMat)方法的返回值

LogistiC 回归梯度上升优化算法

加载数据

1
2
3
4
5
6
7
8
9
10
11
from numpy import *
def loadDataSet():
dataMat = []
labelMat = []
fr = open('F:\\study\\testSet.txt')
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函数

1
2
3
4
5
"""
sigmoid函数
"""
def sigmoid(inX):
return (1.0/(1+exp(-inX)))

LogistiC 梯度上升算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def gredAscent(dataMatIn, classLabels):
#[[x,x,x],...]
dataMatrix = mat(dataMatIn)
#将列表转换为矩阵再倒置
labelMat = mat(classLabels).transpose()
#获取行列
m,n = shape(dataMatrix)
#向目标移动的步长
alpha = 0.001
#迭代次数
maxCycles = 500
#回归系数 n=3行1列的单位数组
weights = ones((n,1))
for k in range(maxCycles):
#h>0.5 在右边 dataMatrix*weights矩阵相乘100行一列
#每次计算所有样本点
h = sigmoid(dataMatrix*weights)
error = (labelMat-h);
#w = w + α▽w f(w)
#dataMatrix.transpose() 3行100列 error 100行1列 相乘后3,1
weights = weights + alpha * dataMatrix.transpose()*error
return weights
  • 1.解析文本,文本中有100个样本点,前两列代表点的数值型特征X1,X2,最后一列为分类标签
  • 2.设置回归系数初始值为1(为单位矩阵,每个样本点对应一个回归系数,设置回归系数行数等于样本点的列数,实现倒置),步长为0.001,训练次数500
  • 3.计算z=wTx,带入sigmod获取结果,将结果与分类标签计算误差值
  • 4.根据误差值方向调整回归系数(梯度迭代公式,梯度简化为数据样本与错误量相乘[见上篇博客公式推导])
1
2
3
4
5
"""
查看效果
"""
dataArr,labelMat = loadDataSet()
weights = gredAscent(dataArr,labelMat)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
"""
分析数据:画出决策边界
"""
import matplotlib.pyplot as plt
def plotBestFit(weights):
dataMat,labelMat = loadDataSet()
dataArr = array(dataMat)
# n = 100
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)
# 画标签为1的点
ax.scatter(xcord1, ycord1, s=30, c='red', marker='p')
# 画标签为0的点
ax.scatter(xcord2, ycord2, s=30, c='green')
#创建决策边界线
x = arange(-3.0, 3.0, 0.1)
"""
设置sigmod函数值为0,0是两个分类的分界处,可解出x,y的关系式
"""
# 0 = w0*x0 + w1*x + w2*y => y = -(w0 + w1*x)/w2
y = (-weights[0]-weights[1]*x)/weights[2] #最佳拟合线
ax.plot(x,y)
plt.xlabel('X1');plt.ylabel('X2');
plt.show()
1
2
3
4
5
6
7
8
9
"""
查看效果
"""
from numpy import *
# 传入返回的回归系数(书中有误,因此修改了plotBestFit的传参,也为了后面随机梯度可共用
#另外需要定义weights将gredAscent的值赋给weights)
%matplotlib inline
# getA()将自身矩阵转化为ndarray类型的变量,等价于asarray(self)
plotBestFit(weights.getA())

分析数据

随机梯度上升算法

1
2
3
4
5
6
7
8
9
10
11
12
13
"""
一次仅用一个样本点来更新回归系数
"""
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
weights = weights + alpha*error*dataMatrix[i]
return weights
1
2
3
4
5
6
"""
查看效果
"""
dataArr,labelMat = loadDataSet()
weights = stocGradAscent0(array(dataArr),labelMat)
plotBestFit(weights)

分析数据

改进的随机梯度上升算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
"""
改进的随机梯度上升算法
alpha在每次迭代的时候都会调整,随着迭代次数不断减小,但永远不会到0
每次从样本中随机取出一个样本更新回归系数,之后将改值从列表中删除,进行下次迭代
"""
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m,n = shape(dataMatrix)
weights = ones(n)
for j in range(numIter):
# 每个样本的编号[0,..,99]
dataIndex = range(m)
for i in range(m):
"""
步长alpha每次迭代时需要调整,每次减少1/(i+j)
档j<<max(i),alpha就不是严格下降的。
避免参数严格下降也常见于模拟退火算法(SAA)等其他优化算法中
"""
alpha = 4/(1.0+j+i)+0.01
# numpy.random.uniform(low,high,size)在给定区间[0,100)内随机取样,注意是左闭右开
# size输出样本数目,int或元组,缺省时输出一个值
randIndex = int(random.uniform(0,len(dataIndex)))
# 求和 即计算z = w0x0+w1*x1+w2*x2 随机选取样本计算h
h = sigmoid(sum(dataMatrix[randIndex]*weights))
error = classLabels[randIndex] - h
weights = weights + alpha * error * dataMatrix[randIndex]
# 样本被使用后去除 在此次迭代内dataIndex长度每次减1
del(dataIndex[randIndex])
return weights
1
2
3
4
5
6
"""
查看效果
"""
dataArr,labelMat = loadDataSet()
weights = stocGradAscent1(array(dataArr),labelMat)
plotBestFit(weights)

分析数据

从疝气病症预测病马的死亡率

处理数据中的缺失值

可选的做法

使用可用特征的均值来填补缺失值;
使用特殊值来填补缺失值,如-1;
忽略有缺失值的样本;
使用相似样本的均值添补缺失值;
使用另外的机器学习算法预测缺失值。

numpy不允许包含缺失值,选择实数0来替换所有缺失值,恰好能适用于Logistic回归
我们需要的是一个在更新是不会影响系数的值,根据回归系数的更新公式
w = w + a e dataMatrix[randIndex],若dataMatrix的某特征对应值为0,则系数不做更新w=w,另外sigmoid(0)=0.5,对结果的预测不具有任何的倾向性

Logistic回归分类函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def classifyVector(inX, weights):
prob = sigmoid(sum(inX*weights))
if prob > 0.5: return 1.0
else: return 0.0
def colicTest():
frTrain = open('F:\study\horseColicTraining.txt')
frTest = open('F:\study\horseColicTest.txt')
trainingSet = []; trainingLabels = []
for line in frTrain.readlines():
currLine = line.strip().split('\t')
lineArr = []
for i in range(21):
lineArr.append(float(currLine[i]))
trainingSet.append(lineArr)
trainingLabels.append(float(currLine[21]))
trainWeights = stocGradAscent1(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(classifyVector(array(lineArr), trainWeights)) != int(currLine[21]):
errorCount += 1
errorRate = (float(errorCount)/numTestVec)
print "the error rate of this test is: %f" % errorRate
return errorRate
def multiTest():
numTests = 10; errorSum=0.0
for k in range(numTests):
errorSum += colicTest()
print "after %d iterations the average error rate is: %f" % (numTests, errorSum/float(numTests))
1
2
3
4
5
6
7
"""
运行时报D:\Anaconda2\lib\site-packages\ipykernel\__main__.py:5:
RuntimeWarning: overflow encountered in exp警告
说明计算的数据结果溢出了,忽略也无妨,查过说可以调整sigmoid函数,
使用longfloat()来解决溢出,但没有解决,还在寻找解决办法。。
"""
multiTest()
D:\Anaconda2\lib\site-packages\ipykernel\__main__.py:5: RuntimeWarning: overflow encountered in exp


the error rate of this test is: 0.298507
the error rate of this test is: 0.402985
the error rate of this test is: 0.268657
the error rate of this test is: 0.298507
the error rate of this test is: 0.283582
the error rate of this test is: 0.402985
the error rate of this test is: 0.388060
the error rate of this test is: 0.328358
the error rate of this test is: 0.388060
the error rate of this test is: 0.417910
after 10 iterations the average error rate is: 0.347761

总结(来自书中)

Logistic回归的目的是寻找一个非线性函数sigmoid的最佳拟合参数,求解过程可以由最优化
算法来完成。在最优化算法中,最常用的就是梯度上升算法,而梯度上升算法又可以简化为随机
梯度上升算法。
随机梯度上升算法与梯度上升算法的效果相当,但占用更少的计算资源。此外,随机梯度上
升是一个在线算法,它可以在新数据到来时就完成参数更新,而不需要重新读取整个数据集来进
行批处理运算。
机器学习的一个重要问题就是如何处理缺失数据。这个问题没有标准答案,取决于实际应用
中的需求。现有一些解决方案,每种方案都各有优缺点。

安 阳 wechat
微信公众号,欢迎关注
创作需要动力
0%