梯度寻优与logistic算法
一、一些基本概念
最优化:在给定约束之下如何寻求某些因素(的量),以使某一(或某些)指标达到最优。高中学过的线性规划就是一类典型的最优化问题。
凸集:在集合空间中,凸集就是一个向四周凸起的图形。用数学语句描述就是:集合边界任意两点连线上的所有点都在这个集合内部。
超平面:能够用于切割已给集合的点集。数学公式为$X={x|c^T=z}$。它的意义在于能够将一个凸集分为两部分。
举例说明。对于二维空间,用一条直线划分给定的散点,则有$y - ax - b = 0 $。它就是一个超平面,“超”在b这个维度上,在这里它是一个定值。同样地,对于三维空间,用一个平面划分,择有超平面$z - ax - by - c = 0$。
支撑超平面:使所有集合内的点位于同一侧的超平面。
凸集分离定理:如果两个凸集没有交叉或重合,则可以用超平面(支撑超平面)分割这两个凸集。该定理为线性分类提供了理论基础。
凸函数:凸函数是凸集中元素的数学特征,是凸集的数学公式表达。用以下公式来表示凸集:
$f(ax_1 + (1 - \alpha x_2)) \le f(\alpha x_1 +f(1 - \alpha) x_2)$
因为凸集是一个集合,没有对元素是否连续进行规定,所以凸函数没有要求是连续的或可微的。
局部最优和全局最优:它实际是函数的极值和最值的问题。对损失函数$\sum (y - f(y))^2$(这里f(y)是用各种算法来计算预测值)来说,我们只想要最小值而不是极值。损失函数的定义借鉴了统计学中样本的二阶中心距的理论和方法。它是连续可导的,因此可以求最值。
二、Logistic回归
1、logistic回归
logistic回归是线性回归的一种扩展,它将线性回归的结果按照sigmoid函数进行分类。在计量模型中,logistic回归是一种无序分类算法,即要求分类变量不是等级有序的。与logistic相反,probit回归则要求分类变量必须是等级有序的。我们仍然可以用线性回归的模型评价方法来检验和优化logistic回归。
logistic是一种线性分类器,无法解决异或问题,因此要求样本尽量是线性可分的。它旨在散点中找到最佳的一条回归线,把所有的散点分到回归线两侧,这条回归线由sigmod函数确定,并由梯度下降算法去迭代实现。
从神经网络角度看,logistic回归算是一种单层单节点(单神经元)感知器,sigmoid函数是激活函数,梯度下降算法是一种优化策略。
2、sigmoid函数
sigmoid函数,或称单极性阈值函数的公式为:
$$f(x) = \frac{1}{1 + e^{-x}},其导数为f'(x) = f(x)(1 - f(x))$$
它有两个作用:一是将线性回归的预测值归一化;二是放大器,即远离回归线的sigmoid值会接近0或1,靠近回归线的值在0.5附近。
3、梯度下降算法
梯度下降算法是一种优化策略。梯度即偏导数,物理意义是因变量取某值时,某个(或所有)自变量(特征)在此刻的分量。
梯度下降算法需要注意三个点:
首先,需要事先声明损失函数。因为损失函数通常是凸函数,并且一定存在最小值。所以所有偏导数同时为0的点一定是极值点。实际上这个条件很难达到,所以通常采用逐步逼近(迭代)法来求极值。
其次,梯度下降算法在每一次迭代时取梯度的负值,直至使损失函数最小。
举例说明。
假如规定更新公式$x = x - \eta * \frac{\triangle y}{\triangle x}$。其中,$\eta$表示学习率(或称步长),$\frac{\triangle f}{\triangle x}$表示x分量的偏导数,f表示多元函数符合函数。那么在梯度下降的每一次迭代中,都会按照公式更新x本身。
如下图所示。在C点时,偏导数值为负,由更新公式,$x = x_c + |\frac{\triangle f}{\triangle x_c|$,知道x将不断增大(往右移动),并最终到达B点。同理,在A点时,偏导数值为正,由更新公式,$x = x_c - |\frac{\triangle f}{\triangle x_c|$,知道x将不断减小(往左移动),并最终到达B点。
import matplotlib.pyplot as plt
import numpy as np x = np.linspace(-2, 2)
y = np.power(x,2) plt.plot(x, y)
plt.annotate(
s="A", xy=(1.5, np.power(1.5, 2)), xycoords="data", color="black",
xytext=(20, 20), textcoords="offset points", fontsize=16,
arrowprops=dict(arrowstyle="->", connectionstyle="arc3, rad=0.2")
)
plt.annotate(
s="C", xy=(-1.5, np.power(-1.5, 2)), xycoords="data", color="red",
xytext=(20, 20), textcoords="offset points", fontsize=16,
arrowprops=dict(arrowstyle="->", connectionstyle="arc3, rad=0.2") )
plt.annotate(
s="B", xy=(0, 0), xycoords="data", color="blue",
xytext=(0, 20), textcoords="offset points", fontsize=16,
arrowprops=dict(arrowstyle="->", connectionstyle="arc3, rad=0.2"), )
plt.scatter(1.5, np.power(1.5, 2), marker="D", c="black")
plt.scatter(-1.5, np.power(-1.5, 2), marker="D", c="red")
plt.scatter(0, 0, marker="D", c="blue")
plt.arrow(-1.5, np.power(-1.5, 2), 1.4, -2.1, width=0.04, color="red")
plt.arrow(1.5, np.power(1.5, 2), -1.4, -2.1, width=0.03, color="black")
plt.show()
图形代码
学习率$\eta$控制每次移动的幅度(步长),如果步长过大,会导致移动过程中会“跳过”B点,并出现来回震荡现象。因此,在众多随机梯度下降算法之外,也会有各种控制步长的优化方法。比如增加动量项等。
对于下图这种多个维度的,按照单个维度进行逐一分析即可。
对每个分量进行独立求偏导并进行迭代,意味着这些分量要相互独立(或要满足最大似然估计)。因此要注意分量(特征列向量)之间的线性相关程度以及共线性问题。
第三,梯度下降算法需要设置激活函数。激活函数解决了线性分类器无法克服的异或问题,使得多个(线性分类器+激活函数)能够圈出多边形,来更细致的对散点进行分类。常见的激活函数有单位阶跃函数、单极性阈值函数、双极性阈值函数等。
第四,梯度下降算法需要使用BP误差调整策略。常见的误差调整策略有:
4、算法流程
初始化每个回归系数(包括常数项),即初始化权重矩阵。
重复计算:
计算整个数据集的梯度
使用梯度下降算法更新回归系数
返回回归系数
三、python3实现logistic回归算法
1、python3实现logistic回归算法
LoadDataSet载入数据集。Plot绘制图形。数据集https://files.cnblogs.com/files/kuaizifeng/testSet.txt.zip。
LgcRegr实现logistic算法。
sigmoid激活函数。也可以改成双极性阈值函数,但相应的算法需要调整。
fit函数:训练数据集。
pred函数:预测分类。
error函数:误差计算。
gd函数[可选]:批量梯度下降,这里没设定batch。
rgd函数[可选]:随机梯度下降。
srgd函数[可选]:增加动量项的随机梯度下降。
drgd函数[可选]:使用delta学习规则作为误差调整策略。需要对神经网络的学习规则有一定的了解。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt class LoadDataSet(object):
def get_dataSet(self):
dataSet = pd.read_csv(
"machinelearninginaction-master/Ch05/testSet.txt",
sep="\t", header=None,
names=["x1", "x2", "y"],
)
data = np.array(dataSet[["x1", "x2"]]).tolist()
labels = list(dataSet["y"])
self.dataSet = dataSet
return data, labels class Plot(object):
def plot(self, dataSet, weights):
"""绘图"""
plt.figure()
Arr0 = dataSet[dataSet["y"] == 0]
Arr1 = dataSet[dataSet["y"] == 1]
plt.scatter(Arr0["x1"], Arr0["x2"], c="blue")
plt.scatter(Arr1["x1"], Arr1["x2"], c="red")
x1_test = np.linspace(-4, 4)
# np.double:从多维单元素的数组中取出单元素值
x2_test = -(np.double(weights[0]) + np.double(weights[1]) * x1_test) / np.double(weights[2])
# 超平面 weights[0] + weight[1]*x1 + weights[2]*x2 = 0,因此得到x2_test
plt.plot(x1_test, np.double(x2_test), c="c")
plt.show() class LgcRegr(LoadDataSet, Plot):
"""梯度下降gradient descent """
def __init__(self):
super().__init__() def sigmoid(self, inX):
"""单极性阈值函数及其导数"""
return 1.0/(1 + np.exp(-inX)) def fit(self, dataSet, labels, **kwargs):
"""训练模型"""
dataMat = np.mat(dataSet)
dataMat = np.c_[np.ones(dataMat.shape[0]), dataMat] # 把dataSet改成矩阵,并增加一列
labelMat = np.mat(labels).T # 标签列
learning_rate = kwargs.get("learning_rate", 0.001)
steps = kwargs.get("steps", 500)
self.weights = getattr(self, kwargs.get("mode", "gd"))(dataMat, labelMat, learning_rate, steps)
return self.weights
def error(self, dataSet, labels):
"""计算误差"""
dataMat = np.mat(dataSet)
dataMat = np.c_[np.ones((dataMat.shape[0], 1)),dataMat]
error = np.dot(dataMat, self.weights) - np.mat(labels).T
return np.double(np.round(sum(np.power(error, 2)), 4)) def pred(self, testSet):
testSet = np.array(testSet)
if not testSet.shape[1] >= 2: # 单个样本要进行处理
testSet = np.mat([testSet])
testSet = np.C_[np.ones((testSet.shape[0], 1)), testSet] # 增加一列常数项
predmat = self.sigmoid(np.dot(testSet, self.weights)) # 预测值矩阵
self.pred = []
for i in range(testSet.shape[0]):
self.pred.append(np.round(np.double(out[i, 0])))
return self.pred def gd(self, dataMat, labelMat, learning_rate, steps):
"""普通随机下降gradient_descent"""
weights = np.ones((dataMat.shape[1], 1))
for i in range(steps):
net = np.dot(dataMat, weights)
weights = weights + learning_rate * dataMat.T * (labelMat - self.sigmoid(net)) # 一次需要计算整个矩阵
# 参见Perceptro学习规则,这里把sgn函数换成了sigmoid函数
return weights
def rgd(self, dataMat, labelMat, learning_rate, steps):
"""随机梯度下降random_gradient_descent"""
weights = np.ones((dataMat.shape[1], 1))
for i in range(steps):
for j, row in enumerate(dataMat):
net = sum(np.dot(row, weights))
weights = weights + learning_rate * row.T * (labelMat[j] - self.sigmoid(net)) # 只计算一行数据
return weights def srgd(self, dataMat, labelMat, learning_rate, steps):
"""随机梯度西下降,增加动量项"""
weights = np.ones((dataMat.shape[1], 1))
for i in range(steps):
for j, _ in enumerate(dataMat):
rate = 4 / (1.0 + j + i) + learning_rate # 更新学习率
index = np.random.randint(0, dataMat.shape[0]) # 随机选择数据行
row = dataMat[index]
net = sum(np.dot(row, weights))
weights = weights + rate * row.T * (labelMat[index] - self.sigmoid(net))
return weights # weights.A可以将矩阵转化为数组 def drgd(self, dataMat, labelMat, learning_rate, steps):
"""用delta学习规则训练"""
weights = np.ones((dataMat.shape[1], 1))
for i in range(steps):
for j, row in enumerate(dataMat):
rate = 4 / (1.0 + j + i) + learning_rate # 更新学习率
# 这里设损失函数为 E = 1/2 * (d - f(X.T * W))^2
net = np.double(np.dot(row, weights)) # 计算W.T * X
error = np.double(labelMat[j]) - self.sigmoid(net) # 计算(d - o)
fd = self.sigmoid(net).T * (1 - self.sigmoid(net)) # 计算 f'(x),这里f是sigmoid
delta = -np.double(error * fd ) * row.T # 计算delta E = (d - o) * f'(x) * X.T
weights = weights - rate * delta # 更新权重 -rate * delta
return weights
运行以下代码:
logis = LgcRegr()
data = logis.get_dataSet()
weights = logis.fit(*data, mode="drgd", steps=100) # mode可以选rgd、gd、srgd
# print(weights)
logis.plot(logis.dataSet, weights)
# logis.error(*data)
结果为:
2、sikit-learn实现logistic回归算法
官网http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html
from sklearn.linear_model import LogisticRegression
import pickle logistic = LogisticRegression()
logistic.fit(*data)
# logistic.sparsify() # 查看模型的参数设置 和logistic.densify()一样
logistic.get_params() # 查看模型的参数设置
logistic.predict_proba(data[0]) # 每个样本对标签的每个类别的所属概率值
# 持久化模型,以后拿来预测即可
pickle.dump(logistic, open("logistic.txt", "wb")) # 保存模型
lgc = pickle.load(open("logistic.txt", "rb")) # 载入模型
logistic.predict(data[0]) # 预测,这里用了原始数据集
logistic.score(*data) # 准确率
梯度寻优与logistic算法的更多相关文章
- 机器学习算法-logistic回归算法
Logistic回归算法调试 一.算法原理 Logistic回归算法是一种优化算法,主要用用于只有两种标签的分类问题.其原理为对一些数据点用一条直线去拟合,对数据集进行划分.从广义上来讲这也是一种多元 ...
- 机器学习——Logistic回归
参考<机器学习实战> 利用Logistic回归进行分类的主要思想: 根据现有数据对分类边界线建立回归公式,以此进行分类. 分类借助的Sigmoid函数: Sigmoid函数图: Sigmo ...
- [机器学习实战-Logistic回归]使用Logistic回归预测各种实例
目录 本实验代码已经传到gitee上,请点击查收! 一.实验目的 二.实验内容与设计思想 实验内容 设计思想 三.实验使用环境 四.实验步骤和调试过程 4.1 基于Logistic回归和Sigmoid ...
- 准备熟悉Kaggle -菜鸟进阶
原文链接http://www.bubuko.com/infodetail-525389.html 1.Kaggle简介 Kaggle是一个数据分析的竞赛平台,网址:https://www.kaggle ...
- 大数据竞赛平台——Kaggle 入门
Reference: http://blog.csdn.net/witnessai1/article/details/52612012 Kaggle是一个数据分析的竞赛平台,网址:https://ww ...
- 支持向量机(SVM)
SVM 简介 SVM:Support Vector Machine , 支持向量机, 是一种分类算法. 同Logistic 分类方法目的一样,SVM 试图想寻找分割线或面,将平面或空间里的样本点一分为 ...
- AI人工智能顶级实战工程师 课程大纲
课程名称 内容 阶段一.人工智能基础 — 高等数学必知必会 1.数据分析 "a. 常数eb. 导数c. 梯度d. Taylore. gini系数f. 信息熵与组合数 ...
- 大数据竞赛平台——Kaggle 入门篇
这篇文章适合那些刚接触Kaggle.想尽快熟悉Kaggle并且独立完成一个竞赛项目的网友,对于已经在Kaggle上参赛过的网友来说,大可不必耗费时间阅读本文.本文分为两部分介绍Kaggle,第一部分简 ...
- 神经网络、logistic回归等分类算法简单实现
最近在github上看到一个很有趣的项目,通过文本训练可以让计算机写出特定风格的文章,有人就专门写了一个小项目生成汪峰风格的歌词.看完后有一些自己的小想法,也想做一个玩儿一玩儿.用到的原理是深度学习里 ...
随机推荐
- jmeter处理json(关联)
例:用户需要登录成功后才可进行充值,进行充值操作时需要获取登录成功返回的sign值,在jmeter中可以通过关联的方式进行处理. jmeter中json path插件的使用方法:http://www. ...
- php 获取 post 请求体参数
private function getPostData() { $postdata = file_get_contents("php://input"); $data = url ...
- [BZOJ2049] [SDOI2008] 洞穴勘测
题目描述 辉辉热衷于洞穴勘测. 某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好两个洞穴.假 ...
- MkDocs 文档生成逻辑浅析
Markdown 和 MkDocs 简介 Markdown 的语法简洁明了.学习容易,而且功能比纯文本更强,因此有很多人用它写博客.世界上最流行的博客平台 WordPress 和大型 CMS 如 Jo ...
- TCP 的保活定时器
引言 可以没有任何数据流过一个空闲的 TCP 连接. 这意味着我们可以启动一个客户与服务器建 立一个连接,然后离去数小时.数天.数个星期或者数月,而连接依然保持.中间路由器可以崩溃和重启,电话线可以被 ...
- iBatis --> MyBatis
从 Clinton Begin 到 Google(从 iBatis 到 MyBatis,从 Apache Software Foundation 到 Google Code),Apache 开源代码项 ...
- Java函数的联级调用
String类的方法可以连续调用: String str="abc"; String result=str.trim().toUpperCase().concat("de ...
- 条目二十三《考虑用排序的vector替代关联容器》
条目二十三<考虑用排序的vector替代关联容器> 在看到这个条目的标题的时候,说实话,我一下子是比较懵逼的.这个结论怎么和数据结构的时间复杂度不一致了? 一般来说,像map,set等关联 ...
- linux开机、重启和用户登陆注销
关机&重启命令 基本介绍: shutdown –h now 立该进行关机 shudown -h 1 "hello, 1 分钟后会关机了" shutdown –r no ...
- linux的sed(增删改查)使用方法
sed的增删改查的基本操作 参考:https://www.cnblogs.com/0zcl/p/6855740.html 01:增(a) 2个sed命令,分别是:(这些操作都是在内存中进行的,所以不会 ...