目录
一、logistic回归的概念
1.线性模型与回归
2.Logistic回归:
3.Sigmoid函数
4.logistic的优缺点:
二、Logistic实现
1.logistic实现一般过程:
2.收集读取数据集并绘制图像
3.用Sigmoid函数寻找边界和参数
4.利用梯度下降算法优化
5.分析数据:画出决策边界
三、课外实验:从疝气病症状预测病马的死亡率
1.准备数据:处理数据中的缺失值
2.利用梯度上升进行分类
3.小结
线性模型一般模式:
回归:
现有一些数据点,我们用 一条直线对这些点进行拟合,该线称为最佳拟合直线,这个拟合过程就称作回归。
Logistic回归(logistic regression)是统计学习中的经典分类方法,属于对数线性模型,所以也被称为对数几率回归。这里要注意,虽然带有回归的字眼,但是该模型是一种分类算法,Logistic回归是一种线性分类器,针对的是线性可分问题。利用logistic回归进行分类的主要思想是:根据现有的数据对分类边界线建立回归公式,以此进行分类。
利用Logistic 回归进行分类的主要思想是:根据现有数据对分类边界线建立回归公式,以此进行分类。这里的 “回归”一词源于最佳拟合,表示要找到最佳拟合参数集。 训练分类器时的做法就是寻找最佳拟合参数,使用的是最优化算法。
Logistic回归来做分类问题,我们想要的函数应该是,能接受所有的输入然后预测出类别。例如,在两个类的情况下,上述函数输出0或1。例如海维塞德阶跃函数 (Heaviside step function),也称为单位阶跃函数。
单位跃函数的问题在于: 该函数在跳跃点上从0瞬间跳跃到1(不连续、不可微),这个瞬间跳跃过程有时很难处理。
但是在数学上,Sigmoid函数可以可以解决这个问题。Sigmoid函数具体的计算公式如下:
下图给出了Sigmoid函数在不同坐标尺度下的两条曲线图。当x为0时,Sigmoid函数值为0.5。 随着x的增大,对应的Sigmoid值将逼近于1;而随着x的减小,Sigmoid值将逼近于0。如果横坐标 刻度足够大,Sigmoid函数看起来很像一个阶跃函数。
所以,为了实现Logistic回归分类,我们可以在每个特征上都乘以一个回归系数,然后把 所有的结果值相加,将这个总和代入Sigmoid函数中,进而得到一个范围在0~1之间的数值。任何大于0.5的数据被分入1类,小于0.5即被归入0类。所以,Logistic回归也可以被看成是一种概率估计。
优点:计算代价不高,易于理解和实现。
缺点:容易欠拟合,分类精度可能不高。
使用数据类型:数值型和标称型数据。
收集数据:任何方式
准备数据:由于要计算距离,因此要求数据都是数值型的,另外结构化数据格式最佳。
分析数据:采用任一方是对数据进行分析
训练算法:大部分时间将用于训练,训练的目的为了找到最佳的分类回归系数
测试算法:一旦训练步骤完成,分类将会很快
使用算法:首先,我们需要输入一些数据,并将其转化成对应的结构化数值;接着基于训练好的回归系数就可以对这些数值进行简单的回归计算,判定它们属于哪一类别;在这之后,我们就可以在输出的类别上做一些其他的分析工作。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
path='D:\machine learning\logdata1.txt'
data=pd.read_csv(path,names=['Exam1','Exam2','Accepted'])
data.head()
#数据可视化
fig,ax=plt.subplots()
ax.scatter(data[data['Accepted'] == 0]['Exam1'], data[data['Accepted'] == 0]['Exam2'], c='r', marker='x', label='y=0')
ax.scatter(data[data['Accepted'] == 1]['Exam1'], data[data['Accepted'] == 1]['Exam2'], c='b', marker='o', label='y=1')
ax.legend()
ax.set_xlabel('exam1')
ax.set_ylabel('exam2')
plt.show()
def get_Xy(data):
# 在第一列插入1
data.insert(0, 'ones', 1)
# 取除最后一列以外的列
X_ = data.iloc[:, 0:-1]
# 取特征值
X = X_.values
# 取最后一列
y_ = data.iloc[:, -1]
y = y_.values.reshape(len(y_), 1)
return X, y
X,y=get_Xy(data)
#损失函数
def sigmoid(z):
return 1/(1+np.exp(-z))
def costFunction(X,y,theta):
A=sigmoid(X@theta)
first=y * np.log(A)
second =(1-y)*np.log(1-A)
#样本的累加
return -np.sum(first+second)/len(X)
theta=np.zeros((3,1))
theta.shape
#输出损失函数
cost_init=costFunction(X,y,theta)
print(cost_init)
#梯度下降
def gradientDescent(X, y, theta, alpha, iters):
m = len(X)
costs = []
for i in range(iters):
A = sigmoid(X @ theta)
# X.T:X的转置
theta = theta - (alpha / m) * X.T @ (A - y)
cost = costFunction(X, y, theta)
costs.append(cost)
if i % 1000 == 0:
print(cost)
return costs, theta
alpha=0.004
iters=200000
costs, theta_final = gradientDescent(X, y, theta, alpha, iters)
print(costs)
def predict(X, theta):
prob = sigmoid(X @ theta)
return [1 if x >= 0.5 else 0 for x in prob]
print(predict(X, theta_final))
y_ = np.array(predict(X, theta_final))
print(y_)
y_pre = y_.reshape(len(y_), 1)
# 求取均值
acc = np.mean(y_pre == y)
print(acc)
print('-----------------------6.决策边界-------------------------------------')
# 决策边界就是Xθ=0的时候
coef1 = - theta_final[0, 0] / theta_final[2, 0]
coef2 = - theta_final[1, 0] / theta_final[2, 0]
x = np.linspace(20, 100, 100)
f = coef1 + coef2 * x
fig, ax = plt.subplots()
ax.scatter(data[data['Accepted'] == 0]['Exam1'], data[data['Accepted'] == 0]['Exam2'], c='r', marker='x', label='y=0')
ax.scatter(data[data['Accepted'] == 1]['Exam1'], data[data['Accepted'] == 1]['Exam2'], c='b', marker='o', label='y=1')
ax.legend()
ax.set_xlabel('exam1')
ax.set_ylabel('exam2')
ax.plot(x, f, c='g')
plt.show()
不知道bug在哪,没有直线,和网上别人的比对了一下不知道代码错在哪,也可能是我没太看明白。
病马数据存放在文件夹中
# 分类函数
def classifyVector(inX, weights):
prob = sigmoid(sum(inX * weights)) # 计算sigmoid值
if prob > 0.5: # 概率大于0.5,返回分类结果1.0
return 1.0
else: # 概率小于等于0.5,返回分类结果0.0
return 0.0
ef colicTest1():
# 读取测试集和训练集,并对数据进行格式化处理
frTrain = open('D:\machine learning\horseColicTraining.txt') # 读取训练集文件
frTest = open('D:\machine learning\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 = gradAscent(array(trainingSet), trainingLabels)
errorCount = 0 # 错误数
numTestVec = 0.0
for line in frTest.readlines(): # 遍历每行数据
numTestVec += 1.0 # 测试集数量加1
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 # 预测结果与真值不一致,错误数加1
errorRate = (float(errorCount) / numTestVec) # 计算错误率
print("测试的错误率为: %f" % errorRate)
return errorRate
# 求结果的平均值
def multiTest():
numTests = 10
errorSum = 0.0
for k in range(numTests):
errorSum += colicTest1()
print("在 %d 迭代之后, 平均错误率为: %f" % (numTests, errorSum / float(numTests)))
本次实验过程,遇到了好几个小问题,比如绘图的时候,拟合曲线不显示的问题,没有注意到x,y的维度问题,导致卡在绘图上半天。
而logistic回归的目的是寻找一个非线性函数Sigmoid的最佳拟合参数,求解过程可以由最优化算法完成。
参考资料:
[1]: 《机器学习实战》Peter Harrington 著
[2]:实验参考