1 主要思想
Logistic回归进行分类的主要思想是:根据现有数据对分类边界线建立回归公式,以此进行分类。这里的“回归”一词源于最佳拟合,表示要找到最佳拟合参数集。
2 sigmoid函数
我们定义逻辑回归的预测函数为
其中𝑔(𝑥)函数是sigmoid函数。
其中𝜃^𝑇𝑥可以看作回归方程
所以,
sigmoid 函数的图像如下:
定义域:R
值域:(0,1)
单调性:
当𝑥→+∞时,𝑦→1
当𝑥→−∞时,𝑦→0
比如现在我找到这个分类边界的曲线,即𝑦=𝜃^𝑇 𝑋,其中𝜃=(𝜃_1,𝜃_2,……𝜃_𝑛)已经确定
0.5作为分类的边界。
令y=𝜃^𝑇 𝑋(其中𝑋代表特征的取值)。
当y≥0的时候g(y)≥0.5,即𝜃^ 𝑇 𝑋≥0 的时候g(𝜃^𝑇 𝑋)≥0.5,我们把它归为1类别。
当𝑍≤0的时候g(Z)≤0.5,即𝜃^ 𝑇 𝑋≤0的时候g(𝜃^𝑇 𝑋)≤0.5, 我们把它归为0类别。
3 决策边界
决策边界(decision boundary),所谓决策边界就是能够把样本正确分类的一条边界,主要有线性决策边界(linear decision boundaries)和非线性决策边界(non-linear decision boundaries)。
3.1 线性决策边界
图中的决策边界:
3.2 非线性决策边界
其中,在决策边界上的点
4 梯度下降法
4.1 梯度和梯度下降法的含义
4.1.1 梯度
梯度的本意是一个向量(矢量),表示某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向(此梯度的方向)变化最快,变化率最大(为该梯度的模)。
梯度有两点非常重要。一是,矢量。二是,沿着梯度的方向,目标函数增加最快。
方向导数
顾名思义,方向导数就是某个方向上的导数
比如下面的图示,在某一点处的方向导数其实是由很多(方向导数即该点处切线)
梯度:是一个矢量,其方向上的方向导数最大,其大小正好是此最大方向导数 。
我们采用的梯度下降法因为求的是目标函数的最小值,所以方向是该点梯度的反方向。
4.1.2 梯度下降法
梯度下降法是一个最优化算法,它是沿梯度下降的方向求解极小值。
4.2 形象理解
以”下山问题”进行类比,更直观的感受梯度下降法。比如现在我的代价函数只和两个参数有关𝜃_0,𝜃_1,我画如下的图形:
假设你站在山的某一处,你现在想以最快速度下山,那你肯定是找一条最陡峭的路走。你环顾四周,找到了一条路线,这个方向是最陡的(梯度方向)。于是你就出发了,走了一会发现,这个方向不是最陡的路了。你就停下来,换了个最陡的方向,继续往下走。重复这个步骤,你最终到达了山脚下。
那么,你从山顶到山脚的整个下山的过程,就是梯度下降。
4.3 如何求解梯度
4.4 梯度下降法算法步骤
4.5 求解梯度
注:
详细求解点击这里
4.6 常见疑问
4.6.1 为什么沿着梯度的反方向代价函数一定会减小?
4.6.2 为什么更新𝜃 的值可以用?
5 Logistic回归的代价函数
5.1 函数展示
分段函数形式:
当𝑦=1, ℎ_𝜃 (𝑥)=1时,𝐶𝑜𝑠𝑡=0 。
当𝑦=1, ℎ_𝜃 (𝑥)=0时,𝐶𝑜𝑠𝑡=∞ 。
当𝑦=0, ℎ_𝜃 (𝑥)=0时,𝐶𝑜𝑠𝑡=0 。
当𝑦=0, ℎ_𝜃 (𝑥)=1时,𝐶𝑜𝑠𝑡=∞。
我们发现当真实值和预测值越接近的时候(也就是模型越好),代价函数越少。所以,我们找到最好的模型就等价于找到最小的代价函数。
5.2 线性回归的代价函数和Logistic回归代价函数不同的原因
线性回归代价函数的实际意义就是平方误差。而逻辑回归却不是,它的预测函数ℎ_𝜃 (𝑥)是非线性的。如果类比地使用线性回归的代价函数于逻辑回归,那𝐽(𝜃)很有可能就是非凸函数,即存在很多局部最优解,但不一定是全局最优解。我们希望构造一个凸函数,也就是一个碗型函数做为逻辑回归的代价函数。
6 小结
6.1 Logistic回归
虽然逻辑回归能够用于分类,不过其本质还是线性回归。它仅在线性回归的基础上,在特征到结果的映射中加入了一层sigmoid函数(非线性)映射,即先把特征线性求和(线性回归),然后使用sigmoid函数来预测。
6.2 多元线性回归表达式
6.3 易错点
易错点1:
这里𝜃_0表示截距项, 𝑥_0 等于1(不是来源于样本的特征数据),是我们给截距的一个系数,称为偏执项。
易错点2:
7 具体案列
用Logistic回归分类器,画出决策边界。
部分数据集如上图。
7.1 步骤
7.1.1 画出散点图
import numpy as np
import matplotlib.pyplot as plt
np.set_printoptions(suppress=True)#显示的数字不是以科学记数法显示
data=np.genfromtxt('testSet.txt')
print(data)
x_data=data[:,:-1]#特征的数据,列的切片,所有的列但是不包括最后一列
# print(x_data)
# print(x_data[1,0])
y_data=data[:,-1]#标签数据
#print(y_data)
def plot():
x0=[]#存放0类别所有样本点的横坐标
x1=[]#存放1类别所有样本点的横坐标
y0=[]#存放0类别所有样本点的纵坐标
y1=[]#存放1类别所有样本点的纵坐标
for i in range(len(x_data)):
if y_data[i]==0:#如果标签为0类别
x0.append(x_data[i,0])#将x_data每个样本点的x轴坐标添加到x0中
y0.append(x_data[i,1])#将x_data每个样本点的y轴坐标添加到y0中
else:
x1.append(x_data[i,0])
y1.append(x_data[i,1])
#画图
plt.scatter(x0,y0,marker='o',color='b',label='label0',s=40)
plt.scatter(x1,y1,marker='*',c='r',label='label1',s=60)
#scatter画散点图,marker标识散点图样式,color标识颜色,label表示图例的解释
plt.legend()#显示图例
plot()
plt.show()
小结:
1.genfromtxt函数读取文件
2.特征数据的切片
3.先分0.1类别,再找横纵坐标
4.用 matplotlib.pyplot包里面的scatter函数画散点图。具体参数如下:marker标识散点图样式,color标识颜色,label表示图例的解释。此外,lenged函数显示图例,show函数展示散点图。
7.1.2 添加偏置项
import numpy as np
np.set_printoptions(suppress=True)#显示的数字不是以科学记数法显示
data=np.genfromtxt('testSet.txt')
x_data=data[:,:-1]#特征数据
y_data=data[:,-1]
m=len(x_data)
#print(m)
#1.为求解最佳的θ,对特征数据进行预处理,添加偏置项
a=np.ones((m,1))
X_data=np.concatenate((a,x_data),axis=1)
#concatenate实现数组拼接,axis=1左右拼接,axis=0上下拼接
#print(X_data)
知识点:
1.数据拼接
数据拼接这里有两种方法:
(1)numpy.append(arr, values, axis=None)函数。
对于参数规定,要么一个数组和一个数值;要么两个数组,不能三个及以上数组直接append拼接。
(2)numpy提供了numpy.concatenate((a1,a2,…), axis=0)函数。能够一次完成多个数组的拼接。
其中a1,a2,…是数组类型的,其中默认是沿纵向拼接,即axis=0,如果要求沿横向拼接,axis=1。
1表示横轴,方向从左到右;0表示纵轴,方向从上到下。
当axis=1时,数组的变化是横向的,体现出列的增加或者减少。
反之,当axis=0时,数组的变化是纵向的,体现出行的增加或减少。
7.1.3 利用梯度下降法求解最优的回归参数
def sigmold(x):
return 1/(1+np.exp(-x))
#2.使用梯度下降法求最佳θ
def gradAscent(xArr,yArr):
#1.定义迭代次数
epochs=30000
#2.给出学习率
lr=0.001
#3.将数组转换为矩阵
xMat=np.mat(xArr)
yMat=np.mat(yArr)
m,n=xMat.shape
#4.给定θ的初始值,开始迭代
a=np.ones((n,1))
theta=np.mat(a)
#print(theta)
for i in range(epochs):
#预测值
h=sigmold(xMat*theta)
#print(h)
theta_grad=xMat.T*(h-yMat.T)/m
theta=theta-lr*theta_grad
return theta
theta=gradAscent(X_data,y_data)
知识点:
1.矩阵和数组是不同的。矩阵的转置和矩阵的乘积是需要借助mat函数。数组的相乘就是对应位子相乘。
例如:
numpy中数组和矩阵的区别:matrix是array的分支,matrix和array在很多时候都是通用的,你用哪一个都一样。但这时候,官方建议大家如果两个可以通用,那就选择array,因为array更灵活,速度更快,很多人把二维的array也翻译成矩阵。但是matrix的优势就是相对简单的运算符号,比如两个矩阵相乘,就是用符号*,但是array相乘不能这么用,得用方法.dot()array的优势就是不仅仅表示二维,还能表示3、4、5…维,而且在大部分Python程序里,array也是更常用的。
利用梯度下降法求解最优的回归参数数学基本原理:
7.1.4 迭代求得最优参数
代码在上一步骤里面。
知识点:
7.1.5 画出决策边界
#画出决策边界
#plot()
x_test=[[-4],[3]]
y_test=(-theta[0]-x_test*theta[1])/theta[2]
print(y_test)
plt.plot(x_test,y_test,'y')
运行结果:
知识点:
8 案列2 使用sklearn 的 Logistic回归
8.1 第一题题目
根据老师女性乳腺癌患者数据集(医学指标)构建逻辑回归分类类型模型进行良性或恶性乳腺癌肿瘤预测
8.1.2 代码
from sklearn.datasets import load_breast_cancer#加载乳腺癌数据集
from sklearn.model_selection import train_test_split#数据集划分
from sklearn import linear_model#导入sklearn里面的线性回归模块!
import numpy as np
np.set_printoptions(suppress=True)#显示的数据不是科学记数法
cancer=load_breast_cancer()
x=cancer.data#特征数据
y=cancer.target#特征数据标签
print(cancer.target_names)#0代表恶性,1代表良性
# print(x)
# print(y)
X_train,X_test,Y_train,Y_test=train_test_split(cancer.data,cancer.target,test_size=0.2)
#定义模型
logistic=linear_model.LogisticRegression(solver='liblinear')
logistic.fit(X_train,Y_train)
print(logistic.score(X_train,Y_train))#训练集的精度
print(logistic.score(X_test,Y_test))#测试集的精度
8.1.3 步骤总结
1 导入包
2 找到特征数据和特征数据标签
3 划分训练集和测试集
4 定义模型
5 求精度
注:
记得导入sklearn里面的线性回归模块
from sklearn import linear_model
8.2 第二题
使用sklearn模块划分下出下图的决策边界。
8.2.1 画出散点图
#载入数据
data=np.genfromtxt('testSet.txt')
x_data=data[:,:-1]
y_data=data[:,-1]
#print('data:',data)
#print('x_data',x_data)
#print('y_data',y_data)
def plot():
x0=[]
x1=[]
y0=[]
y1=[]
for i in range(len(x_data)):
if y_data[i]==0:
x0.append(x_data[i,0])
y0.append(x_data[i,1])
else:
x1.append(x_data[i,0])
y1.append(x_data[i,1])
#画图
plt.scatter(x0,y0,marker='o',c='b',label='label0',s=40)
plt.scatter(x1,y1,marker='*',c='y',label='label1',s=60)
plt.legend()#显示图例
plot()
plt.show()
运行结果:
8.2.2 建立模型、训练模型
logistic=linear_model.LogisticRegression()
#传入的数据不需要在添加偏置项,sklearn里面的logistic回归可以自行处理
logistic.fit(x_data,y_data)
print('截距:',logistic.intercept_)#logistic.intercept_代表截距
print('系数:',logistic.coef_)#coef特征数前面的系数
print(logistic.coef_[0])
print(logistic.coef_[0][0])
运行结果:
8.2.3 画出决策边界
plot()
x_test=np.array([[-4],[3]])
y_test=(-logistic.intercept_-x_test*logistic.coef_[0][0])/logistic.coef_[0][1]
plt.plot(x_test,y_test,'r')
plt.show()
运行结果: