Datawhale组队学习之集成学习——Task4分类问题
前言
一、使用sklearn构建完整的分类项目
1、收集数据集并选择合适的特征
在数据集上我们使用我们比较熟悉的IRIS鸢尾花数据集。
代码如下(示例):
from sklearn import datasets
iris = datasets.load_iris()
X = iris.data
y = iris.target
feature = iris.feature_names
data = pd.DataFrame(X,columns=feature)
data['target'] = y
data.head()
2、选择度量模型性能的指标
- 真阳性TP:预测值和真实值都为正例;
- 真阴性TN:预测值与真实值都为正例;
- 假阳性FP:预测值为正,实际值为负;
- 假阴性FN:预测值为负,实际值为正;
- 准确率:分类正确的样本数占总样本的比例,即: A C C = T P + T N F P + F N + T P + T N ACC = \frac{TP+TN}{FP+FN+TP+TN} ACC=FP+FN+TP+TNTP+TN.
- 精度:预测为正且分类正确的样本占预测值为正的比例,即: P R E = T P T P + F P PRE = \frac{TP}{TP+FP} PRE=TP+FPTP.
- 召回率:预测为正且分类正确的样本占类别为正的比例,即: R E C = T P T P + F N REC = \frac{TP}{TP+FN} REC=TP+FNTP.
- F1值:综合衡量精度和召回率,即: F 1 = 2 P R E × R E C P R E + R E C F1 = 2\frac{PRE\times REC}{PRE + REC} F1=2PRE+RECPRE×REC.
- ROC曲线:以假阳率为横轴,真阳率为纵轴画出来的曲线,曲线下方面积越大越好。
3、选择具体的模型并进行训练
- (1)逻辑回归logistic regression
我们假设逻辑回归模型为: p ( y = 1 ∣ x ) = 1 1 + e − w T x p(y = 1|x) = \frac{1}{1+e^{-w^Tx}} p(y=1∣x)=1+e−wTx1 .
下面我们来具体推导下逻辑回归模型:
假设数据Data { ( x i , y i ) } , i = 1 , 2 , . . . , N , x i ∈ R p , y i ∈ { 0 , 1 } \{(x_i,y_i) \},\;\;i = 1,2,...,N,\;\;x_i \in R^p,y_i \in \{0,1 \} {(xi,yi)},i=1,2,...,N,xi∈Rp,yi∈{0,1},设 p 1 = p ( y = 1 ∣ x ) = σ ( w T ) = 1 1 + e − w T x p_1 = p(y=1|x) = \sigma(w^T) = \frac{1}{1+e^{-w^Tx}} p1=p(y=1∣x)=σ(wT)=1+e−wTx1。因为y只可能取0或者1,因此假设数据服从0-1分布,也叫伯努力分布,即:当y=1时, p ( y ∣ x ) = p 1 p(y|x)=p_1 p(y∣x)=p1,当y=0时, p ( y ∣ x ) = 1 − p 1 p(y|x)=1-p_1 p(y∣x)=1−p1,可以写成 p ( y ∣ x ) = p 1 y ( 1 − p 1 ) 1 − y p(y|x) = p_1^y(1-p_1)^{1-y} p(y∣x)=p1y(1−p1)1−y,可以带入y=0和y=1进去验证,结果和前面的结论一模一样。
我们使用极大似然估计MLE,即:
w ^ = a r g m a x w l o g P ( Y ∣ X ) = a r g m a x x l o g ∏ i = 1 N P ( y i ∣ x i ) = a r g m a x w ∑ i = 1 N l o g P ( y i ∣ x i ) = a r g m a x w ∑ i = 1 N ( y i l o g p 1 + ( 1 − y i ) l o g ( 1 − p 1 ) ) 记 : L ( w ) = ∑ i = 1 N ( y i l o g p 1 + ( 1 − y i ) l o g ( 1 − p 1 ) ) ∂ L ∂ w k = ∑ i = 1 N y i 1 p 1 ∂ p 1 ∂ z ∂ z ∂ w k + ( 1 − y i ) 1 1 − p 1 ( − ∂ p 1 ∂ z ∂ z ∂ w k ) = ∑ i = 1 N y i 1 σ ( z ) ( σ ( z i ) − σ ( z i ) 2 ) x i + ( 1 − y i ) 1 1 − σ ( z i ) [ − ( σ ( z i ) − σ ( z i ) 2 ) x i ] = ∑ i = 1 N [ ( y i − y i σ ( z i ) ) x i + ( 1 − y i ) ( − σ ( z i ) ) x i ] = ∑ i = 1 N y i x i − σ ( z i ) x i = ∑ i = 1 N ( y i − σ ( z i ) ) x i \hat{w} = argmax_w\;\;log\;P(Y|X) = argmax_x\;\;log\;\prod_{i=1}^N P(y_i|x_i) = argmax_w \sum\limits_{i=1}^{N} log\;P(y_i|x_i)\\ \;\;\; = argmax_w \sum\limits_{i=1}^{N}(y_ilog\;p_1 + (1-y_i)log(1-p_1)) \\ 记:L(w) = \sum\limits_{i=1}^{N}(y_ilog\;p_1 + (1-y_i)log(1-p_1))\\ \;\;\; \frac{\partial L}{\partial w_k} = \sum\limits_{i=1}^{N} y_i\frac{1}{p_1}\frac{\partial p_1}{\partial z}\frac{\partial z}{\partial w_k} + (1-y_i)\frac{1}{1-p_1}(-\frac{\partial p_1}{\partial z}\frac{\partial z}{\partial w_k})\\ \;\;\;=\sum\limits_{i=1}^{N}y_i\frac{1}{\sigma(z)}(\sigma(z_i)-\sigma(z_i)^2)x_i + (1-y_i)\frac{1}{1-\sigma(z_i)}[-(\sigma(z_i)-\sigma(z_i)^2)x_i]\\ \;\;\; =\sum\limits_{i=1}^{N}[(y_i-y_i\sigma(z_i))x_i + (1-y_i)(-\sigma(z_i))x_i]\\ \;\;\; = \sum\limits_{i=1}^{N}y_ix_i-\sigma(z_i)x_i = \sum\limits_{i=1}^{N}(y_i-\sigma(z_i))x_i w^=argmaxwlogP(Y∣X)=argmaxxlogi=1∏NP(yi∣xi)=argmaxwi=1∑NlogP(yi∣xi)=argmaxwi=1∑N(yilogp1+(1−yi)log(1−p1))记:L(w)=i=1∑N(yilogp1+(1−yi)log(1−p1))∂wk∂L=i=1∑Nyip11∂z∂p1∂wk∂z+(1−yi)1−p11(−∂z∂p1∂wk∂z)=i=1∑Nyiσ(z)1(σ(zi)−σ(zi)2)xi+(1−yi)1−σ(zi)1[−(σ(zi)−σ(zi)2)xi]=i=1∑N[(yi−yiσ(zi))xi+(1−yi)(−σ(zi))xi]=i=1∑Nyixi−σ(zi)xi=i=1∑N(yi−σ(zi))xi
因此, ∂ L ∂ w k = ∑ i = 1 N ( y i − σ ( z i ) ) x i \frac{\partial L}{\partial w_k} = \sum\limits_{i=1}^{N}(y_i-\sigma(z_i))x_i ∂wk∂L=i=1∑N(yi−σ(zi))xi,由于这里涉及的函数不像线性回归一样能简单求出解析解,因此我们使用迭代的优化算法:梯度下降法,即:
w k ( t + 1 ) ← w k ( t ) − η ∑ i = 1 N ( y i − σ ( z i ) ) x i ( k ) , 其 中 , x i ( k ) 为 第 i 个 样 本 第 k 个 特 征 w_k^{(t+1)}\leftarrow w_k^{(t)} - \eta \sum\limits_{i=1}^{N}(y_i-\sigma(z_i))x_i^{(k)},\;\;\;其中,x_i^{(k)}为第i个样本第k个特征 wk(t+1)←wk(t)−ηi=1∑N(yi−σ(zi))xi(k),其中,xi(k)为第i个样本第k个特征
值得注意的是,逻辑回归在实际中不太用于多分类问题,因为实际效果不是很好 - (2)基于概率的分类模型
线性判别分析
基于数据进行分类时,一个很自然的想法是:将高维的数据降维至一维,然后使用某个阈值将各个类别分开。下面用图的形式展示:
图中,数据的维度是二维的,我们的想法是把数据降维至一维,然后用阈值就能分类。这个似乎是一个很好的想法,我们总是希望降维后的数据同一个类别自身内部方差小,不同类别之间的方差要尽可能大。这也是合理的,因为同一个类别的数据应该更加相似,因此方差小;不同类别的数据之间应该很不相似,这样才能更容易对数据进行分类,我们简称为:类内方差小,类间方差大,在计算机语言叫“松耦合,高内聚”。在做具体的推导之前,我们对数据的形式和一些基本统计量做一些描述:
特征 X = ( x 1 , x 2 , . . . , x N ) T X = (x_1,x_2,...,x_N)^T X=(x1,x2,...,xN)T,因变量 Y = ( y 1 , y 2 , . . . , y N ) T , 其 中 , y i ∈ { + 1 , − 1 } Y = (y_1,y_2,...,y_N)^T,\;\;其中,y_i \in \{+1,-1 \} Y=(y1,y2,...,yN)T,其中,yi∈{+1,−1},类别c1的特征 X c 1 = { x i ∣ y i = + 1 } X_{c_1} = \{x_i|y_i=+1 \} Xc1={xi∣yi=+1},同理,类别c2的特征 X c 2 = { x i ∣ y i = − 1 } X_{c_2} = \{x_i|y_i=-1 \} Xc2={xi∣yi=−1},属于c1类别的数据个数为 N 1 N_1 N1,属于类别c2的数据个数为 N 2 N_2 N2,其中, N 1 + N 2 = N N_1+N_2 = N N1+N2=N。
特征X投影在w方向至一维: z i = w T x i , ∣ ∣ w ∣ ∣ = 1 z_i = w^Tx_i,\;\;||w|| = 1 zi=wTxi,∣∣w∣∣=1
全样本投影的均值 z ˉ = 1 N ∑ i = 1 N z i = 1 N ∑ i = 1 N w T x i \bar{z} = \frac{1}{N}\sum\limits_{i=1}^{N}z_i = \frac{1}{N}\sum\limits_{i=1}^{N}w^Tx_i zˉ=N1i=1∑Nzi=N1i=1∑NwTxi
全样本投影的协方差 S z = 1 N ∑ i = 1 N ( z i − z ˉ ) ( z i − z ˉ ) T = 1 N ∑ i = 1 N ( w T x i − z ˉ ) ( w T x i − z ˉ ) T S_z = \frac{1}{N}\sum\limits_{i=1}^{N}(z_i-\bar{z})(z_i-\bar{z})^T = \frac{1}{N}\sum\limits_{i=1}^{N}(w^Tx_i-\bar{z})(w^Tx_i-\bar{z})^T Sz=N1i=1∑N(zi−zˉ)(zi−zˉ)T=N1i=1∑N(wTxi−zˉ)(wTxi−zˉ)T
c1样本投影的均值 z 1 ˉ = 1 N 1 ∑ i = 1 N 1 z i = 1 N 1 ∑ i = 1 N 1 w T x i \bar{z_1} = \frac{1}{N_1}\sum\limits_{i=1}^{N_1}z_i = \frac{1}{N_1}\sum\limits_{i=1}^{N_1}w^Tx_i z1ˉ=N11i=1∑N1zi=N11i=1∑N1wTxi
c1样本投影的协方差 S z 1 = 1 N 1 ∑ i = 1 N 1 ( z i − z 1 ˉ ) ( z i − z 1 ˉ ) T = 1 N 1 ∑ i = 1 N 1 ( w T x i − z 1 ˉ ) ( w T x i − z 1 ˉ ) T S_{z_1} = \frac{1}{N_1}\sum\limits_{i=1}^{N_1}(z_i-\bar{z_1})(z_i-\bar{z_1})^T = \frac{1}{N_1}\sum\limits_{i=1}^{N_1}(w^Tx_i-\bar{z_1})(w^Tx_i-\bar{z_1})^T Sz1=N11i=1∑N1(zi−z1ˉ)(zi−z1ˉ)T=N11i=1∑N1(wTxi−z1ˉ)(wTxi−z1ˉ)T
c2样本投影的均值 z 2 ˉ = 1 N 2 ∑ i = 1 N 2 z i = 1 N 2 ∑ i = 1 N 2 w T x i \bar{z_2} = \frac{1}{N_2}\sum\limits_{i=1}^{N_2}z_i = \frac{1}{N_2}\sum\limits_{i=1}^{N_2}w^Tx_i z2ˉ=N21i=1∑N2zi=N21i=1∑N2wTxi
c2样本投影的协方差 S z 2 = 1 N 2 ∑ i = 1 N 2 ( z i − z 2 ˉ ) ( z i − z 2 ˉ ) T = 1 N 2 ∑ i = 1 N 2 ( w T x i − z 2 ˉ ) ( w T x i − z 2 ˉ ) T S_{z_2} = \frac{1}{N_2}\sum\limits_{i=1}^{N_2}(z_i-\bar{z_2})(z_i-\bar{z_2})^T = \frac{1}{N_2}\sum\limits_{i=1}^{N_2}(w^Tx_i-\bar{z_2})(w^Tx_i-\bar{z_2})^T Sz2=N21i=1∑N2(zi−z2ˉ)(zi−z2ˉ)T=N21i=1∑N2(wTxi−z2ˉ)(wTxi−z2ˉ)T
类间差距: ( z ˉ 1 − z ˉ 2 ) 2 (\bar{z}_1-\bar{z}_2)^2 (zˉ1−zˉ2)2
类内方差: S 1 + S 2 S_1 + S_2 S1+S2
由于线性判别分析的目标是同一类别内方差小,不同类别之间距离大,因此损失函数定义为:
J ( w ) = ( z ˉ 1 − z ˉ 2 ) 2 s 1 + s 2 = w T ( x ˉ c 1 − x ˉ c 2 ) ( x ˉ c 1 − x ˉ c 2 ) T w w T ( s c 1 + s c 2 ) w w ^ = a r g m a x w J ( w ) J(w) = \frac{(\bar{z}_1-\bar{z}_2)^2}{s_1+s_2} = \frac{w^T(\bar{x}_{c_1}-\bar{x}_{c_2})(\bar{x}_{c_1}-\bar{x}_{c_2})^Tw}{w^T(s_{c_1}+s_{c_2})w}\\ \;\;\; \hat{w} = argmax_w\;J(w) J(w)=s1+s2(zˉ1−zˉ2)2=wT(sc1+sc2)wwT(xˉc1−xˉc2)(xˉc1−xˉc2)Tww^=argmaxwJ(w)
记: S b = ( x ˉ c 1 − x ˉ c 2 ) ( x ˉ c 1 − x ˉ c 2 ) T , S w = ( s c 1 + s c 2 ) S_b = (\bar{x}_{c_1}-\bar{x}_{c_2})(\bar{x}_{c_1}-\bar{x}_{c_2})^T,\;S_w = (s_{c_1}+s_{c_2}) Sb=(xˉc1−xˉc2)(xˉc1−xˉc2)T,Sw=(sc1+sc2),因此 J ( w ) = w T S b w w T S w w J(w) = \frac{w^TS_bw}{w^TS_ww} J(w)=wTSwwwTSbw
让J(w)对w求导等于0,求出: w = S w − 1 ( x ˉ c 1 − x ˉ c 2 ) w = S_w^{-1}(\bar{x}_{c_1}-\bar{x}_{c_2}) w=Sw−1(xˉc1−xˉc2)
朴素贝叶斯
在线性判别分析中,我们假设每种分类类别下的特征遵循同一个协方差矩阵,每两个特征之间是存在协方差的,因此在线性判别分析中各种特征是不是独立的。但是,朴素贝叶斯算法对线性判别分析作进一步的模型简化,它将线性判别分析中的协方差矩阵中的协方差全部变成0,只保留各自特征的方差,也就是朴素贝叶斯假设各个特征之间是不相关的。在之前所看到的偏差-方差理论中,我们知道模型的简化可以带来方差的减少但是增加偏差,因此朴素贝叶斯也不例外,它比线性判别分析模型的方差小,偏差大。虽然简化了模型,实际中使用朴素贝叶斯的案例非常多,甚至多于线性判别分析,例如鼎鼎大名的新闻分类,垃圾邮件分类等。 - (3)决策树
在回归树中,对一个给定的观测值,因变量的预测值取它所属的终端结点内训练集的平均因变量。与之相对应,对于分类树来说,给定一个观测值,因变量的预测值为它所属的终端结点内训练集的最常出现的类。分类树的构造过程与回归树也很类似,与回归树一样,分类树也是采用递归二叉分裂。但是在分类树中,均方误差无法作为确定分裂节点的准则,一个很自然的替代指标是分类错误率。分类错误率就是:此区域内的训练集中非常见类所占的类别,即:
E = 1 − m a x k ( p ^ m k ) E = 1-max_k(\hat{p}_{mk}) E=1−maxk(p^mk)
上式中的 p ^ m k \hat{p}_{mk} p^mk代表第m个区域的训练集中第k类所占的比例。但是在大量的事实证明:分类错误率在构建决策树时不够敏感,一般在实际中用如下两个指标代替:
(1) 基尼系数:
G = ∑ k = 1 K p ^ m k ( 1 − p ^ m k ) G = \sum\limits_{k=1}^{K} \hat{p}_{mk}(1-\hat{p}_{mk}) G=k=1∑Kp^mk(1−p^mk)
在基尼系数的定义中,我们发现这个指标衡量的是K个类别的总方差。不难发现,如果所有的 p ^ m k \hat{p}_{mk} p^mk的取值都接近0或者1,基尼系数会很小。因此基尼系数被视为衡量结点纯度的指标----如果他的取值小,那就意味着某个节点包含的观测值几乎来自同一个类别。
由基尼系数作为指标得到的分类树叫做:CART。
(2) 交叉熵:
可以替代基尼系数的指标是交叉熵,定义如下:
D = − ∑ k = 1 K p ^ m k l o g p ^ m k D = -\sum\limits_{k=1}^{K} \hat{p}_{mk}log\;\hat{p}_{mk} D=−k=1∑Kp^mklogp^mk
显然,如果所有的 p ^ m k \hat{p}_{mk} p^mk都接近于0或者1,那么交叉熵就会接近0。因此,和基尼系数一样,如果第m个结点的纯度越高,则交叉熵越小。事实证明,基尼系数和交叉熵在数值上时很接近的。
决策树分类算法的完整步骤:
a. 选择最优切分特征j以及该特征上的最优点s:
遍历特征j以及固定j后遍历切分点s,选择使得基尼系数或者交叉熵最小的(j,s)
b. 按照(j,s)分裂特征空间,每个区域内的类别为该区域内样本比例最多的类别。
c. 继续调用步骤1,2直到满足停止条件,就是每个区域的样本数小于等于5。
d. 将特征空间划分为J个不同的区域,生成分类树。 - (4)支持向量机SVM:
支持向量机SVM是20世纪90年代在计算机界发展起来的一种分类算法,在许多问题中都被证明有较好的效果,被认为是适应性最广的算法之一。
支持向量机的基本原理非常简单,如图所视,白色和蓝色的点各为一类,我们的目标是找到一个分割平面将两个类别分开。通常来说,如果数据本身是线性可分的,那么事实上存在无数个这样的超平面。这是因为给定一个分割平面稍微上移下移或旋转这个超平面,只要不接触这些观测点,仍然可以将数据分开。一个很自然的想法就是找到最大间隔超平面,即找到一个分割平面距离最近的观测点最远。下面我们来严格推导:
我们根据距离超平米那最近的点,只要同时缩放w和b可以得到: w T x 1 + b = 1 w^Tx_1 + b = 1 wTx1+b=1与 w T x 2 + b = − 1 w^Tx_2+b = -1 wTx2+b=−1,因此:
w T x 1 + b = 1 w T x 2 + b = − 1 ( w T x 1 + b ) − ( w T x 2 + b ) = 2 w T ( x 1 − x 2 ) = 2 w T ( x 1 − x 2 ) = ∥ w ∥ 2 ∥ x 1 − x 2 ∥ 2 cos θ = 2 ∥ x 1 − x 2 ∥ 2 cos θ = 2 ∥ w ∥ 2 d 1 = d 2 = ∥ x 1 − x 2 ∥ 2 cos θ 2 = 2 ∥ w ∥ 2 2 = 1 ∥ w ∥ 2 d 1 + d 2 = 2 ∥ w ∥ 2 \begin{array}{l} w^{T} x_{1}+b=1 \\ w^{T} x_{2}+b=-1 \\ \left(w^{T} x_{1}+b\right)-\left(w^{T} x_{2}+b\right)=2 \\ w^{T}\left(x_{1}-x_{2}\right)=2 \\ \qquad \begin{array}{l} w^{T}\left(x_{1}-x_{2}\right)=\|w\|_{2}\left\|x_{1}-x_{2}\right\|_{2} \cos \theta=2 \\ \left\|x_{1}-x_{2}\right\|_{2} \cos \theta=\frac{2}{\|w\|_{2}} \end{array} \\ \qquad \begin{array}{l} d_{1}=d_{2}=\frac{\left\|x_{1}-x_{2}\right\|_{2} \cos \theta}{2}=\frac{\frac{2}{\|w\|_{2}}}{2}=\frac{1}{\|w\|_{2}} \\ d_{1}+d_{2}=\frac{2}{\|w\|_{2}} \end{array} \end{array} wTx1+b=1wTx2+b=−1(wTx1+b)−(wTx2+b)=2wT(x1−x2)=2wT(x1−x2)=∥w∥2∥x1−x2∥2cosθ=2∥x1−x2∥2cosθ=∥w∥22d1=d2=2∥x1−x2∥2cosθ=2∥w∥22=∥w∥21d1+d2=∥w∥22
由此可知道SVM模型的具体形式:
min w , b 1 2 ∥ w ∥ 2 s.t. y ( i ) ( w T x ( i ) + b ) ≥ 1 , i = 1 , … , n \begin{aligned} \min _{w, b} & \frac{1}{2}\|w\|^{2} \\ \text { s.t. } & y^{(i)}\left(w^{T} x^{(i)}+b\right) \geq 1, \quad i=1, \ldots, n \end{aligned} w,bmin s.t. 21∥w∥2y(i)(wTx(i)+b)≥1,i=1,…,n
可以将约束条件写为: $g_{i}(w)=-y{(i)}\left(w{T} x^{(i)}+b\right)+1 \leq 0 $
可以将优化问题拉格朗日化
L ( w , b , α ) = 1 2 ∥ w ∥ 2 − ∑ i = 1 n α i [ y ( i ) ( w T x ( i ) + b ) − 1 ] \mathcal{L}(w, b, \alpha)=\frac{1}{2}\|w\|^{2}-\sum_{i=1}^{n} \alpha_{i}\left[y^{(i)}\left(w^{T} x^{(i)}+b\right)-1\right] L(w,b,α)=21∥w∥2−i=1∑nαi[y(i)(wTx(i)+b)−1]
因此:
L ( w , b , α ) = 1 2 ∥ w ∥ 2 − ∑ i = 1 n α i [ y ( i ) ( w T x ( i ) + b ) − 1 ] \mathcal{L}(w, b, \alpha)=\frac{1}{2}\|w\|^{2}-\sum_{i=1}^{n} \alpha_{i}\left[y^{(i)}\left(w^{T} x^{(i)}+b\right)-1\right] L(w,b,α)=21∥w∥2−i=1∑nαi[y(i)(wTx(i)+b)−1]
欲构造 dual 问题, 首先求拉格朗日化的问题中 $\mathrm{w} $ 和 $\mathrm{b} $ 的值, 对 $ \mathrm{w}$ 求梯度, 令梯度为 0, 可求得 w:
对 b 求梯度, 令梯度为 0, 可得:
∂ ∂ b L ( w , b , α ) = ∑ i = 1 n α i y ( i ) = 0 \frac{\partial}{\partial b} \mathcal{L}(w, b, \alpha)=\sum_{i=1}^{n} \alpha_{i} y^{(i)}=0 ∂b∂L(w,b,α)=i=1∑nαiy(i)=0
将 w \mathrm{w} w 带入拉格朗日化的原问题可得
L ( w , b , α ) = ∑ i = 1 n α i − 1 2 ∑ i , j = 1 n y ( i ) y ( j ) α i α j ( x ( i ) ) T x ( j ) − b ∑ i = 1 n α i y ( i ) L ( w , b , α ) = ∑ i = 1 n α i − 1 2 ∑ i , j = 1 n y ( i ) y ( j ) α i α j ( x ( i ) ) T x ( j ) \begin{array}{l} \mathcal{L}(w, b, \alpha)=\sum_{i=1}^{n} \alpha_{i}-\frac{1}{2} \sum_{i, j=1}^{n} y^{(i)} y^{(j)} \alpha_{i} \alpha_{j}\left(x^{(i)}\right)^{T} x^{(j)}-b \sum_{i=1}^{n} \alpha_{i} y^{(i)} \\ \mathcal{L}(w, b, \alpha)=\sum_{i=1}^{n} \alpha_{i}-\frac{1}{2} \sum_{i, j=1}^{n} y^{(i)} y^{(j)} \alpha_{i} \alpha_{j}\left(x^{(i)}\right)^{T} x^{(j)} \end{array} L(w,b,α)=∑i=1nαi−21∑i,j=1ny(i)y(j)αiαj(x(i))Tx(j)−b∑i=1nαiy(i)L(w,b,α)=∑i=1nαi−21∑i,j=1ny(i)y(j)αiαj(x(i))Tx(j)
因此:
对拉格朗日化的原问题求最小值, 得到了 w , 现在可以构造 dual 问題 max α W ( α ) = ∑ i = 1 n α i − 1 2 ∑ i , j = 1 n y ( i ) y ( j ) α i α j ⟨ x ( i ) , x ( j ) ⟩ s.t. α i ≥ 0 , i = 1 , … , n ∑ i = 1 n α i y ( i ) = 0 可以推导出 b的值为: b ∗ = − max i : y ( i ) = − 1 w ∗ T x ( i ) + min i : y ( i ) = 1 w ∗ T x ( i ) 2 SVM的决策子如下,值的符号为类别. w T x + b = ( ∑ i = 1 n α i y ( i ) x ( i ) ) T x + b = ∑ i = 1 n α i y ( i ) ⟨ x ( i ) , x ⟩ + b \begin{aligned} &\text { 对拉格朗日化的原问题求最小值, 得到了 } \mathrm{w} \text { , 现在可以构造 dual 问題 }\\ &\begin{aligned} \max _{\alpha} & W(\alpha)=\sum_{i=1}^{n} \alpha_{i}-\frac{1}{2} \sum_{i, j=1}^{n} y^{(i)} y^{(j)} \alpha_{i} \alpha_{j}\left\langle x^{(i)}, x^{(j)}\right\rangle \\ \text { s.t. } & \alpha_{i} \geq 0, \quad i=1, \ldots, n \\ & \sum_{i=1}^{n} \alpha_{i} y^{(i)}=0 \end{aligned}\\ &\text { 可以推导出 b的值为: } b^{*}=-\frac{\max _{i: y^{(i)}=-1} w^{* T} x^{(i)}+\min _{i: y^{(i)}=1} w^{* T} x^{(i)}}{2}\\ &\begin{array}{r} \text { SVM的决策子如下,值的符号为类别. } \\ \qquad w^{T} x+b=\left(\sum_{i=1}^{n} \alpha_{i} y^{(i)} x^{(i)}\right)^{T} x+b=\sum_{i=1}^{n} \alpha_{i} y^{(i)}\left\langle x^{(i)}, x\right\rangle+b \end{array} \end{aligned} 对拉格朗日化的原问题求最小值, 得到了 w , 现在可以构造 dual 问題 αmax s.t. W(α)=i=1∑nαi−21i,j=1∑ny(i)y(j)αiαj⟨x(i),x(j)⟩αi≥0,i=1,…,ni=1∑nαiy(i)=0 可以推导出 b的值为: b∗=−2maxi:y(i)=−1w∗Tx(i)+mini:y(i)=1w∗Tx(i) SVM的决策子如下,值的符号为类别. wTx+b=(∑i=1nαiy(i)x(i))Tx+b=∑i=1nαiy(i)⟨x(i),x⟩+b
在刚刚的讨论中,我们都是着重讨论了线性支持向量机是如何工作的,但是在现实生活中,我们很难碰到线性可分的数据集,如:
Φ : X ↦ X ^ = Φ ( x ) Φ ( [ x i 1 , x i 2 ] ) = [ x i 1 , x i 2 , x i 1 x i 2 , x i 1 2 , x i 2 2 ] \begin{array}{l} \Phi: \mathcal{X} \mapsto \hat{\mathcal{X}}=\Phi(\mathbf{x}) \\ \Phi\left(\left[x_{i 1}, x_{i 2}\right]\right)=\left[x_{i 1}, x_{i 2}, x_{i 1} x_{i 2}, x_{i 1}^{2}, x_{i 2}^{2}\right] \end{array} Φ:X↦X^=Φ(x)Φ([xi1,xi2])=[xi1,xi2,xi1xi2,xi12,xi22]
如果我们使用上面公式的形式将低维数据拓展至高维数据,则必须面临一个很大的问题,那就是:维度爆炸导致的计算量太大的问题。假如是一个2维特征的数据,我们可以将其映射到5维来做特征的内积,如果原始空间是三维,可以映射到到19维空间,似乎还可以处理。但是如果我们的低维特征是100个维度,1000个维度呢?那么我们要将其映射到超级高的维度来计算特征的内积。这时候映射成的高维维度是爆炸性增长的,这个计算量实在是太大了,而且如果遇到无穷维的情况,就根本无从计算了。能不能呢个避免这个问题呢?核函数隆重登场:
回顾线性可分SVM的优化目标函数:
m i n ⏟ α 1 2 ∑ i = 1 , j = 1 m α i α j y i y j x i ∙ x j − ∑ i = 1 m α i s . t . ∑ i = 1 m α i y i = 0 0 ≤ α i ≤ C \underbrace{ min }_{\alpha} \frac{1}{2}\sum\limits_{i=1,j=1}^{m}\alpha_i\alpha_jy_iy_jx_i \bullet x_j - \sum\limits_{i=1}^{m}\alpha_i\\ s.t. \; \sum\limits_{i=1}^{m}\alpha_iy_i = 0\\ 0 \leq \alpha_i \leq C α min21i=1,j=1∑mαiαjyiyjxi∙xj−i=1∑mαis.t.i=1∑mαiyi=00≤αi≤C
注意到上式低维特征仅仅以内积 x i ∙ x j x_i \bullet x_j xi∙xj 的形式出现,如果我们定义一个低维特征空间到高维特征空间的映射 ϕ \phi ϕ,将所有特征映射到一个更高的维度,让数据线性可分,我们就可以继续按前两篇的方法来优化目标函数,求出分离超平面和分类决策函数了。也就是说现在的SVM的优化目标函数变成:
min ⏟ α 1 2 ∑ i = 1 , j = 1 m α i α j y i y j ϕ ( x i ) ∙ ϕ ( x j ) − ∑ i = 1 m α i s. t . ∑ i = 1 m α i y i = 0 0 ≤ α i ≤ C \begin{array}{c} \underbrace{\min }_{\alpha} \frac{1}{2} \sum_{i=1, j=1}^{m} \alpha_{i} \alpha_{j} y_{i} y_{j} \phi\left(x_{i}\right) \bullet \phi\left(x_{j}\right)-\sum_{i=1}^{m} \alpha_{i} \\ \text { s. } t . \sum_{i=1}^{m} \alpha_{i} y_{i}=0 \\ 0 \leq \alpha_{i} \leq C \end{array} α min21∑i=1,j=1mαiαjyiyjϕ(xi)∙ϕ(xj)−∑i=1mαi s. t.∑i=1mαiyi=00≤αi≤C
可以看到,和线性可分SVM的优化目标函数的区别仅仅是将内积 x i ∙ x j x_i \bullet x_j xi∙xj替换为 ϕ ( x i ) ∙ ϕ ( x j ) \phi(x_i) \bullet \phi(x_j) ϕ(xi)∙ϕ(xj)。我们要将其映射到超级高的维度来计算特征的内积。这时候映射成的高维维度是爆炸性增长的,这个计算量实在是太大了,而且如果遇到无穷维的情况,就根本无从计算了。下面引入核函数:
假设 ϕ \phi ϕ是一个从低维的输入空间 χ \chi χ(欧式空间的子集或者离散集合)到高维的希尔伯特空间的 H \mathcal{H} H映射。那么如果存在函数 K ( x , z ) K(x,z) K(x,z),对于任意 x , z ∈ χ x, z \in \chi x,z∈χ,都有:
K ( x , z ) = ϕ ( x ) ∙ ϕ ( z ) K(x, z) = \phi(x) \bullet \phi(z) K(x,z)=ϕ(x)∙ϕ(z)
那么我们就称 K ( x , z ) K(x, z) K(x,z)为核函数。
仔细发现, K ( x , z ) K(x, z) K(x,z)的计算是在低维特征空间来计算的,它避免了在刚才我们提到了在高维维度空间计算内积的恐怖计算量。也就是说,我们可以好好享受在高维特征空间线性可分的利益,却避免了高维特征空间恐怖的内积计算量。下面介绍几种常用的核函数:
(1) 多项式核函数:
多项式核函数(Polynomial Kernel)是线性不可分SVM常用的核函数之一,表达式为:
K ( x i , x j ) = ( ⟨ x i , x j ⟩ + c ) d K\left(\mathbf{x}_{i}, \mathbf{x}_{j}\right)=\left(\left\langle\mathbf{x}_{i}, \mathbf{x}_{j}\right\rangle+c\right)^{d} K(xi,xj)=(⟨xi,xj⟩+c)d
C用来控制低阶项的强度,C=0,d=1代表无核函数。
(2) 高斯核函数:
高斯核函数(Gaussian Kernel),在SVM中也称为径向基核函数(Radial Basis Function,RBF),它是非线性分类SVM最主流的核函数。libsvm默认的核函数就是它。表达式为:
K ( x i , x j ) = exp ( − ∥ x i − x j ∥ 2 2 2 σ 2 ) K\left(\mathbf{x}_{i}, \mathbf{x}_{j}\right)=\exp \left(-\frac{\left\|\mathbf{x}_{i}-\mathbf{x}_{j}\right\|_{2}^{2}}{2 \sigma^{2}}\right) K(xi,xj)=exp(−2σ2∥xi−xj∥22)
使用高斯核函数之前需要将特征标准化,因此这里衡量的是样本之间的相似度。
(3) Sigmoid核函数:
Sigmoid核函数(Sigmoid Kernel)也是线性不可分SVM常用的核函数之一,表达式为:
K ( x i , x j ) = tanh ( α x i ⊤ x j + c ) K\left(\mathbf{x}_{i}, \mathbf{x}_{j}\right)=\tanh \left(\alpha \mathbf{x}_{i}^{\top} \mathbf{x}_{j}+c\right) K(xi,xj)=tanh(αxi⊤xj+c)
此时的SVM相当于没有隐藏层的简单神经网络。
(4) 余弦相似度核:
常用于衡量两段文字的余弦相似度,表达式为:
K ( x i , x j ) = x i ⊤ x j ∥ x i ∥ ∥ x j ∥ K\left(\mathbf{x}_{i}, \mathbf{x}_{j}\right)=\frac{\mathbf{x}_{i}^{\top} \mathbf{x}_{j}}{\left\|\mathbf{x}_{i}\right\|\left\|\mathbf{x}_{j}\right\|} K(xi,xj)=∥xi∥∥xj∥xi⊤xj
二、示例
1、代码示例
逻辑回归:
# 逻辑回归
penalty {‘l1’, ‘l2’, ‘elasticnet’, ‘none’}, default=’l2’正则化方式
dual bool, default=False 是否使用对偶形式,当n_samples> n_features时,默认dual = False。
C float, default=1.0
solver {‘newton-cg’, ‘lbfgs’, ‘liblinear’, ‘sag’, ‘saga’}, default=’lbfgs’
l1_ratio float, default=None
'''
from sklearn.linear_model import LogisticRegression
log_iris = LogisticRegression()
log_iris.fit(X,y)
log_iris.score(X,y)
线性判别分析:
# 线性判别分析
'''
参数:
solver:{'svd','lsqr','eigen'},默认='svd'
solver的使用,可能的值:
'svd':奇异值分解(默认)。不计算协方差矩阵,因此建议将此求解器用于具有大量特征的数据。
'lsqr':最小二乘解,可以与收缩结合使用。
'eigen':特征值分解,可以与收缩结合使用。
'''
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
lda_iris = LinearDiscriminantAnalysis()
lda_iris.fit(X,y)
lda_iris.score(X,y)
朴素贝叶斯:
# 朴素贝叶斯
from sklearn.naive_bayes import GaussianNB
NB_iris = GaussianNB()
NB_iris.fit(X, y)
NB_iris.score(X,y)
决策树算法对iris分类:
# 使用决策树算法对iris分类:
'''
criterion:{“gini”, “entropy”}, default=”gini”
max_depth:树的最大深度。
min_samples_split:拆分内部节点所需的最少样本数
min_samples_leaf :在叶节点处需要的最小样本数。
'''
from sklearn.tree import DecisionTreeClassifier
tree_iris = DecisionTreeClassifier(min_samples_leaf=5)
tree_iris.fit(X,y)
tree_iris.score(X,y)
支持向量机SVM:
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
'''
C:正则化参数。正则化的强度与C成反比。必须严格为正。惩罚是平方的l2惩罚。
kernel:{'linear','poly','rbf','sigmoid','precomputed'},默认='rbf'
degree:多项式和的阶数
gamma:“ rbf”,“ poly”和“ Sigmoid”的内核系数。
shrinking:是否软间隔分类,默认true
'''
svc_iris = make_pipeline(StandardScaler(), SVC(gamma='auto'))
svc_iris.fit(X, y)
svc_iris.score(X,y)
评估模型的性能并调参:
# 使用网格搜索进行超参数调优:
# 方式1:网格搜索GridSearchCV()
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC
import time
start_time = time.time()
pipe_svc = make_pipeline(StandardScaler(),SVC(random_state=1))
param_range = [0.0001,0.001,0.01,0.1,1.0,10.0,100.0,1000.0]
param_grid = [{'svc__C':param_range,'svc__kernel':['linear']},{'svc__C':param_range,'svc__gamma':param_range,'svc__kernel':['rbf']}]
gs = GridSearchCV(estimator=pipe_svc,param_grid=param_grid,scoring='accuracy',cv=10,n_jobs=-1)
gs = gs.fit(X,y)
end_time = time.time()
print("网格搜索经历时间:%.3f S" % float(end_time-start_time))
print(gs.best_score_)
print(gs.best_params_)
# 方式2:随机网格搜索RandomizedSearchCV()
from sklearn.model_selection import RandomizedSearchCV
from sklearn.svm import SVC
import time
start_time = time.time()
pipe_svc = make_pipeline(StandardScaler(),SVC(random_state=1))
param_range = [0.0001,0.001,0.01,0.1,1.0,10.0,100.0,1000.0]
param_grid = [{'svc__C':param_range,'svc__kernel':['linear']},{'svc__C':param_range,'svc__gamma':param_range,'svc__kernel':['rbf']}]
# param_grid = [{'svc__C':param_range,'svc__kernel':['linear','rbf'],'svc__gamma':param_range}]
gs = RandomizedSearchCV(estimator=pipe_svc, param_distributions=param_grid,scoring='accuracy',cv=10,n_jobs=-1)
gs = gs.fit(X,y)
end_time = time.time()
print("随机网格搜索经历时间:%.3f S" % float(end_time-start_time))
print(gs.best_score_)
print(gs.best_params_)
当类别为两类时,可以绘制混淆矩阵与ROC曲线:
# 混淆矩阵:
# 加载数据
df = pd.read_csv("http://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data",header=None)
'''
乳腺癌数据集:569个恶性和良性肿瘤细胞的样本,M为恶性,B为良性
'''
# 做基本的数据预处理
from sklearn.preprocessing import LabelEncoder
X = df.iloc[:,2:].values
y = df.iloc[:,1].values
le = LabelEncoder() #将M-B等字符串编码成计算机能识别的0-1
y = le.fit_transform(y)
le.transform(['M','B'])
# 数据切分8:2
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,stratify=y,random_state=1)
from sklearn.svm import SVC
pipe_svc = make_pipeline(StandardScaler(),SVC(random_state=1))
from sklearn.metrics import confusion_matrix
pipe_svc.fit(X_train,y_train)
y_pred = pipe_svc.predict(X_test)
confmat = confusion_matrix(y_true=y_test,y_pred=y_pred)
fig,ax = plt.subplots(figsize=(2.5,2.5))
ax.matshow(confmat, cmap=plt.cm.Blues,alpha=0.3)
for i in range(confmat.shape[0]):
for j in range(confmat.shape[1]):
ax.text(x=j,y=i,s=confmat[i,j],va='center',ha='center')
plt.xlabel('predicted label')
plt.ylabel('true label')
plt.show()
# 绘制ROC曲线:
from sklearn.metrics import roc_curve,auc
from sklearn.metrics import make_scorer,f1_score
scorer = make_scorer(f1_score,pos_label=0)
gs = GridSearchCV(estimator=pipe_svc,param_grid=param_grid,scoring=scorer,cv=10)
y_pred = gs.fit(X_train,y_train).decision_function(X_test)
#y_pred = gs.predict(X_test)
fpr,tpr,threshold = roc_curve(y_test, y_pred) ###计算真阳率和假阳率
roc_auc = auc(fpr,tpr) ###计算auc的值
plt.figure()
lw = 2
plt.figure(figsize=(7,5))
plt.plot(fpr, tpr, color='darkorange',
lw=lw, label='ROC curve (area = %0.2f)' % roc_auc) ###假阳率为横坐标,真阳率为纵坐标做曲线
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([-0.05, 1.0])
plt.ylim([-0.05, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic ')
plt.legend(loc="lower right")
plt.show()
2、作业
(1)回归问题和分类问题的联系和区别,如何利用回归问题理解分类问题
- 分类和回归的区别在于输出变量的类型。
定量输出称为回归,或者说是连续变量预测;
定性输出称为分类,或者说是离散变量预测。 - 回归问题通常是用来预测一个值,如预测房价、未来的天气情况等等,例如一个产品的实际价格为500元,通过回归分析预测值为499元,我们认为这是一个比较好的回归分析。一个比较常见的回归算法是线性回归算法(LR)。另外,回归分析用在神经网络上,其最上层是不需要加上softmax函数的,而是直接对前一层累加即可。回归是对真实值的一种逼近预测。
- 分类问题是用于将事物打上一个标签,通常结果为离散值。例如判断一幅图片上的动物是一只猫还是一只狗,分类通常是建立在回归之上,分类的最后一层通常要使用softmax函数进行判断其所属类别。分类并没有逼近的概念,最终正确结果只有一个,错误的就是错误的,不会有相近的概念。最常见的分类方法是逻辑回归,或者叫逻辑分类。
(2)为什么分类问题的损失函数可以是交叉熵而不是均方误差
- 度量分类模型的指标和回归的指标有很大的差异,首先是因为分类问题本身的因变量是离散变量,因此像定义回归的指标那样,单单衡量预测值和因变量的相似度可能行不通。其次,在分类任务中,我们对于每个类别犯错的代价不尽相同。
- 在分类问题中,由于因变量是类别变量而不是连续变量,因此用均方误差显然不合适。
- 神经网络中如果预测值与实际值的误差越大,那么在反向传播训练的过程中,各种参数调整的幅度就要更大,从而使训练更快收敛,如果预测值与实际值的误差小,各种参数调整的幅度就要小,从而减少震荡。使用平方误差损失函数,误差增大参数的梯度会增大,但是当误差很大时,参数的梯度就会又减小了。而使用交叉熵损失是函数,误差越大参数的梯度也越大,能够快速收敛。
(3)线性判别分析和逻辑回归在估计参数方面有什么异同点
(4)尝试从0推导SVM
- 见统计学习方法SVM章节
(5)二次判别分析,线性判别分析,朴素贝叶斯之间的联系和区别
- Linear Discriminant Analysis(线性判别分析)(discriminant_analysis.LinearDiscriminantAnalysis) 和 Quadratic Discriminant Analysis (二次判别分析)(discriminant_analysis.QuadraticDiscriminantAnalysis) 是两个经典的分类器。 正如他们名字所描述的那样,他们分别代表了线性决策平面和二次决策平面。线性判别分析只能学习线性边界, 而二次判别分析则可以学习二次函数的边界,因此它相对而言更加灵活。
- 典型判别是根据方差分析思想,进行投影,将原来一个维度空间的自变量组合投影到另一维度空间,寻找一个由原始变量组成的线性函数使得组间差异和组内差异的比值最大化。根据样本点计算判别函数,计算判别函数到各类中心的欧式距离,取距离最小的类别。贝叶斯判别是利用已知的先验概率去推证将要发生的后验概率,就是计算每个样本的后验概率及其判错率,用最大后验概率来划分样本的分类并使得期望损失达到最小。
- 典型判别不考虑样本的具体分布,只求组间差异和组内差异的比值最大化,贝叶斯判别从样本的多元分布出发,充分利用多元正态分布的概率密度提供的信息计算后验概率,因此需要样本数据服从多元正态分布,方差齐性等。
- 典型判别根据K类最多产生K-1个判别函数,贝叶斯判别根据K类最多可产生K个判别函数
- 在线性判别分析中,我们假设每种分类类别下的特征遵循同一个协方差矩阵,每两个特征之间是存在协方差的,因此在线性判别分析中各种特征是不是独立的。但是,朴素贝叶斯算法对线性判别分析作进一步的模型简化,它将线性判别分析中的协方差矩阵中的协方差全部变成0,只保留各自特征的方差,也就是朴素贝叶斯假设各个特征之间是不相关的。
(6)使用python+numpy实现逻辑回归
- 1、简述:实现逻辑回归
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize as op
#S函数
def sigmoid(z):
g = 1/(1+np.exp(-z))
return g
#cost计算函数
def costFunction(theta, X, y):
theta = np.array(theta).reshape((np.size(theta),1))
m = np.size(y)
h = sigmoid(np.dot(X, theta))
J = 1/m*(-np.dot(y.T, np.log(h)) - np.dot((1-y.T), np.log(1-h)))
return J.flatten()
def gradient(theta, X, y):
theta = np.array(theta).reshape((np.size(theta), 1))
m = np.size(y)
h = sigmoid(np.dot(X, theta))
grad = 1/m*np.dot(X.T, h - y)
return grad.flatten()
#读取数据,第一列是成绩1,第二列是成绩2,第三列是yes/no
data = np.loadtxt('ex2data1.txt', delimiter=',', dtype='float')
m = np.size(data[:, 0])
# print(data)
#绘制样本点
X = data[:, 0:2]
y = data[:, 2:3]
pos = np.where(y == 1)[0]
neg = np.where(y == 0)[0]
X1 = X[pos, 0:2]
X0 = X[neg, 0:2]
plt.plot(X1[:, 0], X1[:, 1], 'k+')
plt.plot(X0[:, 0], X0[:, 1], 'yo')
plt.xlabel('Exam 1 score')
plt.ylabel('Exam 2 score')
#求解最优解
one = np.ones(m)
X = np.insert(X, 0, values=one, axis=1)
initial_theta = np.zeros(np.size(X, 1))
result = op.minimize(fun=costFunction, x0=initial_theta, args=(X, y), method='TNC', jac=gradient)
# print(result)
theta = result.x
cost = result.fun
print('theta:', theta)
print('cost:', cost)
#绘制决策边界
plot_x = np.array([np.min(X[:, 1]), np.max(X[:, 2])])
# print(plot_x)
plot_y = (-1/theta[2])*(theta[1]*plot_x+theta[0])
# print(plot_y)
plt.plot(plot_x,plot_y)
plt.legend(labels=['Admitted', 'Not admitted'])
plt.axis([30, 100, 30, 100])
plt.show()
#预测[45 85]成绩的学生,并计算准确率
theta = np.array(theta).reshape((np.size(theta),1))
z = np.dot([1, 45, 85], theta)
prob = sigmoid(z)
print('For a student with scores 45 and 85, we predict an admission probability of ', prob)
p = np.round(sigmoid(np.dot(X,theta)))
acc = np.mean(p==y)*100
print('Train Accuracy: ',acc,'%')
theta: [-25.1613187 0.20623159 0.20147149]
cost: [0.2034977]
For a student with scores 45 and 85, we predict an admission probability of [0.77629062]
Train Accuracy: 89.0 %
2、简述:通过正规化实现逻辑回归。
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize as op
#S函数
def sigmoid(z):
g = 1/(1+np.exp(-z))
return g
#cost计算函数
def costFunction(theta, X, y, lamb):
theta = np.array(theta).reshape((np.size(theta), 1))
m = np.size(y)
h = sigmoid(np.dot(X, theta))
J = 1/m*(-np.dot(y.T, np.log(h)) - np.dot((1-y.T), np.log(1-h)))
# 添加项
theta2 = theta[1:, 0]
Jadd = lamb/(2*m)*np.sum(theta2**2)
J = J + Jadd
return J.flatten()
#求梯度
def gradient(theta, X, y, lamb):
theta = np.array(theta).reshape((np.size(theta), 1))
m = np.size(y)
h = sigmoid(np.dot(X, theta))
grad = 1/m*np.dot(X.T, h - y)
#添加项
theta[0,0] = 0
gradadd = lamb/m*theta
grad = grad + gradadd
return grad.flatten()
#求特征矩阵
def mapFeature(X1, X2):
degree = 6
out = np.ones((np.size(X1),1))
for i in range(1, degree+1):
for j in range(0, i+1):
res = np.multiply(np.power(X1, i-j), np.power(X2, j))
out = np.insert(out, np.size(out[0, :]), values=res, axis=1)
return out
#读取数据,第一列是成绩1,第二列是成绩2,第三列是yes/no
data = np.loadtxt('ex2data2.txt', delimiter=',', dtype='float')
m = np.size(data[:, 0])
#绘制样本点
X = data[:, 0:2]
y = data[:, 2:3]
pos = np.where(y == 1)[0]
neg = np.where(y == 0)[0]
X1 = X[pos, 0:2]
X0 = X[neg, 0:2]
plt.plot(X1[:, 0], X1[:, 1], 'k+')
plt.plot(X0[:, 0], X0[:, 1], 'yo')
plt.xlabel('Microchip Test 1')
plt.ylabel('Microchip Test 2')
plt.legend(labels=['y = 1', 'y = 0'])
#数据初始化
X = mapFeature(X[:, 0], X[:, 1])
# print(X)
lamb = 1
initial_theta = np.zeros(np.size(X, 1))
#求解最优解
result = op.minimize(fun=costFunction, x0=initial_theta, args=(X, y, lamb), method='TNC', jac=gradient)
# print(result)
cost = result.fun
theta = result.x
print('theta:', theta)
print('cost:', cost)
#绘制决策边界
u = np.linspace(-1, 1.5, 50)
v = np.linspace(-1, 1.5, 50)
z = np.zeros((np.size(u),np.size(v)))
theta = np.array(theta).reshape((np.size(theta), 1))
for i in range(0, np.size(u)):
for j in range(0, np.size(v)):
z[i, j] = np.dot(mapFeature(u[i], v[j]), theta)
# print(z)
plt.contour(u, v, z.T, [0])
plt.show()
#计算准确率
p = np.round(sigmoid(np.dot(X,theta)))
acc = np.mean(p==y)*100
print('Train Accuracy: ',acc,'%')
theta: [ 1.27271026 0.62529965 1.18111686 -2.019874 -0.91743189 -1.43166928
0.12393227 -0.36553118 -0.35725405 -0.17516292 -1.45817009 -0.05098417
-0.61558559 -0.27469165 -1.19271298 -0.24217841 -0.20603302 -0.04466177
-0.27778948 -0.29539513 -0.45645982 -1.04319154 0.02779373 -0.29244864
0.01555759 -0.32742404 -0.14389149 -0.92467489]
cost: [0.52900273]
Train Accuracy: 83.05084745762711 %
(7)了解梯度下降法,牛顿法,拟牛顿法与SOM算法等优化算法
- 见统计学习方法相关章节
参考
【1】https://www.cnblogs.com/orangecyh/p/11678702.html
【2】https://www.bilibili.com/video/BV1Mb4y1o7ck
from=search&seid=6085778383215596866
【3】https://github.com/datawhalechina/ensemble-learning