目录
一.Logicstic回归的一般过程
1.logicstic:
2.sigmoid函数
2.1:Logicstic回归:分类问题
2.2 Logicstic回归:极大似然法
二.基于最优化方法的最佳回归系数确定
2.1.梯度上升法
2.1.1Logicstic回归梯度上升优化算法:
2.1.2 分析数据:画出决策边界
2.1.3 训练算法: 随机梯度上升
2.1.4 改进的随机梯度上升算法
三.实例:从疝气病症预测病马的死亡率
四.总结
(1)收集数据;(2)准备数据;(3)分析数据;(4)训练算法;(5)测试算法;(6)使用算法;
Logicstic回归分类主要思想:根据现有数据对分类边界线建立回归公式,以此分类。
这里的“回归”表示要找到最佳拟合参数集,训练分类器时的做法就是寻找最佳拟合参数,使用的是最优化算法。
优点:计算代价不高,易于理解和实现
缺点:容易欠拟合,分类精度可能不高
适用数据类型:数值型和标称型数据
Sigmoid函数是一种阶跃函数( step function )。在数学中,如果实数域上的某个函数可以用半开区间上的指示函数的有限次线性组合来表示,那么这个函数就是阶跃函数。而数学中指示函数(indicator function)是定义在某集合X上的函数,表示其中有哪些元素属于某一子集A。
具体计算公式为:
为了实现Logistic回归分类器,我们在每个特征上都乘以一个回归系数,然后把所有的结果值相加,将这个总和代人Sigmoid函数中,进而得到一个范围在0~1之间的数值。任何大于0.5的数据被分入1类,小于0.5即被归入0类。所以,Logistic回归也可以被看成是一种概率估计。
对数线性回归是 g(∙)=ln(∙) 时广义/多维线性模型的特例。ny= wx + b
Sigmoid函数的输出记为z,公式为:
运用Sigmoid函数:
梯度上升法基于的思想是:要找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻。函数f(x,y)的梯度可表示为:
梯度上升算法在梯度的方向上移动每个点。 从点 P0 开始,计算完该店的梯度,并且函数移动到下一点P1。 然后在 P1 处重新计算梯度,然后函数移动到 P2。 这个循环重复直到满足停止条件。 梯度算子总是确保我们朝着最好的方向前进。
代码展示:
def loadDataSet():
dataMat = []; labelMat = []
fr = open('D:/pycharm/实验/test/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
def sigmoid(inX):
return 1.0 / (1 + np.exp(-inX))
def gradAscent(dataMatIn, classLabels):
dataMatrix = np.mat(dataMatIn) #转换为numpy矩阵数据类型
labelMat = np.mat(classLabels).transpose() #转换为numpy矩阵数据类型
m, n = np.shape(dataMatrix) #返回dataMatrix的大小,m为函数
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
结果展示:
以上已经解决了一组回归系数,它确定了不同类别数据之间的分割线
画出数据集和Logicstic回归最佳拟合直线的函数
def plotBestFit(weights):
import matplotlib.pyplot as plt
dataMat, labelMat = loadDataSet()
dataArr = np.array(dataMat)
n = np.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 = np.arange(-3.0, 3.0, 0.1)
y = (-weights[0]-weights[1]*x)/weights[2]
ax.plot(x, y)
plt.title('BestFit')
plt.xlabel('X1'); plt.ylabel('X2')
plt.show()
def gradAscent(dataMatIn, classLabels):
dataMatrix = np.mat(dataMatIn) #转换为numpy矩阵数据类型
labelMat = np.mat(classLabels).transpose() #转换为numpy矩阵数据类型
m, n = np.shape(dataMatrix) #返回dataMatrix的大小,m为函数
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.getA()
运行结果:
梯度上升算法在每次回归系数时都需要遍历整个数据集,该方法在处理100个左右的数据集时还可,但如果有数十亿样本和成千上万的特征,那么该方法的计算复杂度就太高了。改进方法是一次仅用一个样本点来更新回归系数,该方法称为随机梯度上升算法
def stocGradAscent0(dataMatrix, classLabels):
m, n = np.shape(dataMatrix)
alpha = 0.01
weights = np.ones(n) #initialize to all ones
for i in range(m):
h = sigmoid(sum(dataMatrix[i]*weights))
error = classLabels[i] - h
weights = weights + alpha * error * dataMatrix[i]
return weights
随机梯度算法在上述数据集的执行结果,最佳拟合直线并不是最佳分类线
改进的地方:(1)alpha在每次迭代的时候都会调整,这会缓解数据波动或高频波动。虽然alpha会随着迭代次数不断减小,但永远不会减小到0,这是因为alpha中还存在一个常数项,必须这样做的原因是为了保证在多次迭代之后刷新数据仍然具有一定的影响
(2)这里通过随机选取样本来更新回归系数,这种方法将减少周期性的波动
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m, n = np.shape(dataMatrix)
weights = np.ones(n) #参数初始化
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
alpha = 4/(1.0+j+i)+0.0001 #降低alpha的大小
randIndex = int(np.random.uniform(0, len(dataIndex)))#go to 0 because of the constant
h = sigmoid(sum(dataMatrix[randIndex]*weights))
error = classLabels[randIndex] - h #计算误差
weights = weights + alpha * error * dataMatrix[randIndex] #更新回归系数
del(dataIndex[randIndex]) #删除已使用的样本
return weights
结果图:
使用逻辑回归(Logicstic),不需要做很多事情来对实例进行分类。 所要做的就是把测试集上每个特征向量乘以最优化方法得来的回归函数,再将该乘积结果求和,最后输入到Sigmoid函数中即可。如果对应的Sigmoid大于0.5就预测类别标签为1,否则为0
def classifyVector(inX, weights):
prob = sigmoid(sum(inX*weights))
if prob > 0.5: return 1.0
else: return 0.0
def colicTest():
frTrain = open('D:/pycharm/实验/test/horseColicTraining.txt'); frTest = open('D:/pycharm/实验/test/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(np.array(trainingSet), trainingLabels, 1000)
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(np.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)))
结果运行效果:
从上面结果可以看出,10次迭代之后的平均错误率为35%
1.逻辑回归(Logicstic)的目的是寻找一个 非线性函数Sigmoid的最佳拟合参数。 求解过程可以由最优化算法来找到最佳拟合参数。 在最优化算法中,最常见的算法之一是梯度上升。 梯度上升算法又可以简化为随机梯度上升。
2.随机梯度上升算法和梯度上升算法效果相当,但随机梯度上升算法占用更少的计算资源。 另外,随机梯度上升是一种在线算法, 它可以随着新数据到来时就完成参数更新,而不需要重新加载整个数据集来进行批处理运算
3.机器学习中的一个主要问题是如何处理缺失值数据。 这个问题没有标准答案。 取决于实际应用中的需求。 有多种解决方案,每个解决方案都有自己的解决方案的优点和缺点。
注:此博客的所有代码都是基于《机器学习实战》