目录
一、Logistic回归概述
1.利用Logistic回归进行分类的主要思想:
根据现有数据对分类边界线建立回归公式,以此进行分类。
2.Logistic回归的优缺点及适用范围:
优点:计算代价不高,易于理解和实现。
缺点:容易欠拟合,分类精度可能不高。
适用数据类型:数值型和标称型数据。
3.Logistic回归的一般流程:
(1)收集数据
(2)准备数据:由于需要进行距离的计算,因此准备的数据应该是数值型的,结构化数据格式最佳。
(3)分析数据:对数据进行分析。
(4)训练算法:大部分时间用于训练,目的是为了找到最佳的分类回归系数。
(5)测试算法:一旦训练步骤完成,分类就会很快。
(6)使用算法:首先,输入一些数据,并将其转化成对应的结构化数值;接着,基于训练好的回归系数,可以对这些数值进行简单的回归计算,判定它们属于哪个类别;之后,我们就可以在输出的类别上做一些其他的分析工作。
4.分类器的函数形式:
Sigmoid函数:
为了实现Logistic回归分类器,我们可以在每个特征上都乘以一个回归系数,然后把所有结果值相加,将这个总和代入Sigmoid函数中,得到一个[0,1]的数值。
5.梯度上升:
基本思想:沿着某函数的梯度方向探寻找到该函数的最大值。
梯度上升算法到达每个点后都会重新估计移动的方向。从 P0 开始,计算完该点的梯度,函数就根据梯度移动到下一点 P1。在 P1 点,梯度再次被重新计算,并沿着新的梯度方向移动到 P2 。如此循环迭代,直到满足停止条件。迭代过程中,梯度算子总是保证我们能选取到最佳的移动方向。
二、Logistic回归
1.数据集介绍:
14.56 7.38 1
25.52 5.63 1
32.42 11.01 1
34.23 2.12 1
28.66 3.38 1
25.55 43.22 0
25.23 43.10 0
25.44 44.12 0
24.54 43.38 0
25.55 41.63 0
24.55 43.01 0
22.56 25.38 1
23.52 34.63 1
15.42 22.01 1
24.23 18.12 1
26.66 12.38 1
15.55 33.22 0
22.23 33.90 0
21.44 34.22 0
14.54 46.38 0
18.55 31.53 0
13.55 29.25 0
本实验采用的是一个简单的数据集
2.训练算法:使用梯度上升找到最佳参数:
(1)优化算法
from numpy import *
import matplotlib.pyplot as plt
import pandas as pd
# Logistic回归梯度上升优化算法
def loadDataSet():
dataMat = []; labelMat = []
fr = open('data/testSet.txt')
for line in fr.readlines():
lineArr = line.strip().split()
# 每行的前两个值是X1和X2
dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
# 对应的类标签
labelMat.append(int(lineArr[2]))
return dataMat, labelMat
# 用于全批量随机梯度上升算法的Sigmoid函数,因为传入值是一个向量,不能比较大小
def gradAscentSigmoid(inX):
return 1.0 / (1 + exp(-inX))
def gradAscent(dataMatIn, classLabels):
# 将输入数据转换成Numpy矩阵数据类型
dataMatrix = mat(dataMatIn)
labelMat = mat(classLabels).transpose()
m, n = shape(dataMatrix)
# 向目标移动的步长
alpha = 0.001
# 迭代次数,for循环迭代完成后将返回训练好的回归系数
maxCycles = 500
weights = ones((n, 1))
for k in range(maxCycles):
# h为一个列向量,[m,n]*[n,1] = [m,1]
h = gradAscentSigmoid(dataMatrix * weights)
# 真实值与预测值之差
error = (labelMat - h)
weights = weights + alpha * dataMatrix.transpose() * error
return weights
(2)测试
dataArr,labelMat=loadDataSet()
gradAscent(dataArr,labelMat)
(3)结果
3.分析数据:画出决策边界:
(1)相关函数
# 画出数据集和Logistic回归最佳拟合直线的函数
def plotBestFit(weights):
# 得到数据集列表和类标签列表
dataMat, labelMat = loadDataSet()
# 将由列表存储的数据集转换为array类型
dataArr = array(dataMat)
# 样本的个数
n = shape(dataArr)[0]
# 定义两个空数组,用来存放不同label的x1(x)和x2(y)值
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(0.0, 30.0, 0.1)
# 设置sigmoid函数为0,0=W0X0+W1X1+W2X2,解出X1,X2的关系式得到分割线方程(为方便计算,X0=1)
y = (-weights[0] - weights[1] * x) / weights[2]
ax.plot(x, y)
plt.xlabel('X1');plt.ylabel('X2');plt.show()
(2)测试
dataArr,labelMat=loadDataSet()
weights=gradAscent(dataArr,labelMat)
plotBestFit(weights.getA())
(3)结果
4.训练算法:随机梯度上升:
(1)梯度上升算法
# 改进的随机梯度上升算法
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m, n = shape(dataMatrix)
weights = ones(n)
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
alpha = 4 / (1.0 + j + i) + 0.01
randIndex = int(random.uniform(0, len(dataIndex)))
h = gradAscentSigmoid(sum(dataMatrix[randIndex] * weights))
error = classLabels[randIndex] - h
weights = weights + alpha * error * dataMatrix[randIndex]
# 删除已使用的样本
del(dataIndex[randIndex])
return weights
(2)测试
dataArr,labelMat=loadDataSet()
weights=stocGradAscent1(array(dataArr),labelMat)
plotBestFit(weights)
(3)结果
程序运行后得到与之前类似的结果图,该图中的分割线达到了与gradAscent()差不多的效果,但是所使用的计算量更少。
5.完整代码:
from numpy import *
import matplotlib.pyplot as plt
import pandas as pd
# Logistic回归梯度上升优化算法
def loadDataSet():
dataMat = []; labelMat = []
fr = open('data/testSet.txt')
for line in fr.readlines():
lineArr = line.strip().split()
# 每行的前两个值是X1和X2
dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
# 对应的类标签
labelMat.append(int(lineArr[2]))
return dataMat, labelMat
# 用于全批量随机梯度上升算法的Sigmoid函数,因为传入值是一个向量,不能比较大小
def gradAscentSigmoid(inX):
return 1.0 / (1 + exp(-inX))
'''
# 用改进的随机梯度上升算法替换该算法 #
def gradAscent(dataMatIn, classLabels):
# 将输入数据转换成Numpy矩阵数据类型
dataMatrix = mat(dataMatIn)
labelMat = mat(classLabels).transpose()
m, n = shape(dataMatrix)
# 向目标移动的步长
alpha = 0.001
# 迭代次数,for循环迭代完成后将返回训练好的回归系数
maxCycles = 500
weights = ones((n, 1))
for k in range(maxCycles):
# h为一个列向量,[m,n]*[n,1] = [m,1]
h = gradAscentSigmoid(dataMatrix * weights)
# 真实值与预测值之差
error = (labelMat - h)
weights = weights + alpha * dataMatrix.transpose() * error
return weights
'''
# 画出数据集和Logistic回归最佳拟合直线的函数
def plotBestFit(weights):
# 得到数据集列表和类标签列表
dataMat, labelMat = loadDataSet()
# 将由列表存储的数据集转换为array类型
dataArr = array(dataMat)
# 样本的个数
n = shape(dataArr)[0]
# 定义两个空数组,用来存放不同label的x1(x)和x2(y)值
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(0.0, 30.0, 0.1)
# 设置sigmoid函数为0,0=W0X0+W1X1+W2X2,解出X1,X2的关系式得到分割线方程(为方便计算,X0=1)
y = (-weights[0] - weights[1] * x) / weights[2]
ax.plot(x, y)
plt.xlabel('X1');plt.ylabel('X2');plt.show()
# 改进的随机梯度上升算法
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m, n = shape(dataMatrix)
weights = ones(n)
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
alpha = 4 / (1.0 + j + i) + 0.01
randIndex = int(random.uniform(0, len(dataIndex)))
h = gradAscentSigmoid(sum(dataMatrix[randIndex] * weights))
error = classLabels[randIndex] - h
weights = weights + alpha * error * dataMatrix[randIndex]
# 删除已使用的样本
del(dataIndex[randIndex])
return weights
dataArr,labelMat=loadDataSet()
weights=stocGradAscent1(array(dataArr),labelMat)
plotBestFit(weights)
参考教材:
机器学习实战