Logistic回归 & Softmax回归
——《 Python机器学习算法:原理,实现与案例》读书笔记
相关数据集:
链接:https://pan.baidu.com/s/1fBNk7mbqCczKawmOyk491Q
提取码:niz2
概述:
Logistic回归虽然名为回归,实为分类算法,用于处理二分类问题
Sotfmax回归是在Logistic回归的基础上推广得到的,用于处理多元分类问题
Logistic回归
线性分类器
先从简单的二维平面的二分类问题开始
如下图所示:
在二维平面内存在两种类别的样本,我们可以找到一条直线,将这两种样本尽可能好得划分开
假
设
直
线
方
程
为
:
假设直线方程为:
假设直线方程为:
w
T
x
+
b
=
0
w
,
b
∈
R
w^{T}x+b=0 \qquad w,b\in R
wTx+b=0w,b∈R
直
线
上
方
的
点
都
满
足
:
w
T
x
+
b
>
k
直线上方的点都满足:w^{T}x+b>k
直线上方的点都满足:wTx+b>k
而
直
线
下
方
的
点
都
满
足
:
w
T
x
+
b
<
k
其
中
k
为
常
数
而直线下方的点都满足:w^{T}x+b<k \qquad 其中k为常数
而直线下方的点都满足:wTx+b<k其中k为常数
这意味着,我们可以根据找出的这条直线,判断样本的类别
设
z
为
样
本
的
类
别
(
0
,
1
)
设z为样本的类别(0,1)
设z为样本的类别(0,1)
z
=
{
0
,
w
T
x
+
b
=
<
k
1
,
w
T
x
+
b
=
>
k
z=\begin{cases} 0,w^{T}x+b=<k\\ 1,w^{T}x+b=>k \end{cases}
z={0,wTx+b=<k1,wTx+b=>k
对于多维空间的分类问题,类似上述问题,我们只需要找到一个超平面,可以将所有样本尽可能好得划分开(类似SVM)
假
设
超
平
面
方
程
为
:
假设超平面方程为:
假设超平面方程为:
w
T
x
+
b
=
0
w
∈
R
n
,
b
∈
R
w^{T}x+b=0 \qquad w\in R^{n},b\in R
wTx+b=0w∈Rn,b∈R
类似的,根据此函数的输出函数值,我们可以实现对样本的分类
logistic函数
对于二维平面的二分类问题,最理想的分类函数显然为单位阶跃函数:
H
(
z
)
=
{
1
,
z
≥
0
0
,
z
≤
0
H(z) = \begin{cases} 1,\qquad z \ge 0\\ 0, \qquad z \le 0 \end{cases}
H(z)={1,z≥00,z≤0
但此函数有一个严重的缺点:不连续–>不是处处可微(有些算法就不可以运用)
logistic函数便是一直常用的替代函数
σ
(
z
)
=
1
1
+
e
−
z
\sigma (z) = \frac{1}{1+e^{-z}}
σ(z)=1+e−z1
概率意义
logistic是一种sigmoid函数,其值域在(0,1)之间连续
函数的输出可以视为x条件下样本分类为y=1的条件概率
P
(
y
=
1
∣
x
)
=
σ
(
g
(
x
)
)
=
1
1
+
e
w
T
+
b
P(y=1|x)=\sigma(g(x)) = \frac{1}{1+e^{w^{T}+b}}
P(y=1∣x)=σ(g(x))=1+ewT+b1
对数概率函数
在统计学中,几率(odds) 定义为:事件发生的概率与事件不发生概率的比值
几率表示的是样本作为正例的相对可能性
对数几率:
l
o
g
p
1
−
p
log \frac{p}{1-p}
log1−pp对数几率大于0表明正例的概率大,大于0表明负例的概率大
logistic回归模型假设一个实例为正例的对数几率是 输入(x)的线性函数
l
o
g
p
1
−
p
=
w
T
x
+
b
log \frac{p}{1-p} = w^{T}x+b
log1−pp=wTx+b
反求p得:
p
=
σ
(
g
(
x
)
)
=
1
1
+
e
−
(
w
T
+
b
)
p = \sigma (g(x)) = \frac {1}{1+e^{-(w^{T}+b)}}
p=σ(g(x))=1+e−(wT+b)1
一阶导数
d σ ( z ) d z = σ ( z ) ( 1 − σ ( z ) ) \frac{\mathrm{d} \sigma (z)}{\mathrm{d} z} = \sigma(z)(1-\sigma(z)) dzdσ(z)=σ(z)(1−σ(z))
Logistic回归模型
Logistic回归模型假设函数为:
h
w
,
b
(
x
)
=
σ
(
g
(
x
)
)
=
1
1
+
e
−
(
w
T
x
+
b
)
h_{w,b}(x) = \sigma (g(x)) = \frac{1}{1+e^{-(w^{T}x+b)}}
hw,b(x)=σ(g(x))=1+e−(wTx+b)1
通常将b作为w0纳入权向量w,同时为输入向量添加常数1作为x0:
w
=
(
b
,
w
1
,
w
2
,
.
.
.
,
w
n
)
T
x
=
(
1
,
x
1
,
x
2
,
.
.
.
,
x
n
)
T
w = (b,w_{1},w_{2},...,w_{n})^{T} \\ x = (1,x_{1},x_{2},...,x_{n})^{T}
w=(b,w1,w2,...,wn)Tx=(1,x1,x2,...,xn)T
此时,logistic函数为:
h
w
(
x
)
=
σ
(
g
(
x
)
)
=
1
1
+
e
−
(
w
T
x
)
h_{w}(x) = \sigma (g(x)) = \frac{1}{1+e^{-(w^{T}x)}}
hw(x)=σ(g(x))=1+e−(wTx)1
h
w
(
x
)
的
输
出
为
预
测
x
为
正
例
的
概
率
,
通
过
训
练
可
以
确
定
模
型
参
数
w
,
构
建
二
元
分
类
函
数
:
h_{w}(x)的输出为 预测x 为正例的概率,通过训练可以确定模型参数w,构建二元分类函数:
hw(x)的输出为预测x为正例的概率,通过训练可以确定模型参数w,构建二元分类函数:
H
(
h
w
(
x
)
)
=
{
1
,
h
w
(
x
)
≥
0.5
0
,
h
w
(
x
)
≤
0.5
H(h_{w}(x)) = \begin{cases} 1,\qquad h_{w}(x)\ge 0.5 \\ 0,\qquad h_{w}(x)\le 0.5 \end{cases}
H(hw(x))={1,hw(x)≥0.50,hw(x)≤0.5
极大似然法估计参数
对于给定的包含m个样本的数据集D,可以使用极大似然法估计w
易
知
,
模
型
将
输
入
实
例
x
i
预
测
为
y
i
的
概
率
为
:
易知,模型将输入实例x_{i}预测为y_{i}的概率为:
易知,模型将输入实例xi预测为yi的概率为:
P ( y = y i ∣ x i ; w ) = h w ( x i ) y i ( 1 − h w ( x i ) 1 − y i ) y i = 0 , 1 P(y=y_{i}|x_{i};w) = h_{w}(x_{i})^{y_{i}}(1-h_{w}(x_{i})^{1-y_{i}})\qquad y_{i}=0,1 P(y=yi∣xi;w)=hw(xi)yi(1−hw(xi)1−yi)yi=0,1
定 义 似 然 函 数 为 : \href{https://www.zhihu.com/question/54082000}{定义似然函数为:} 定义似然函数为:
L ( w ) = ∏ i = 1 m P ( y = y i ∣ x i ; w ) L(w) = \prod_{i=1}^{m} P(y=y_{i}|x_{i};w) L(w)=i=1∏mP(y=yi∣xi;w)
比 较 L o w 的 写 法 : L ( w ) = h w ( x i ) k ( 1 − h w ( x i ) ) n − k n , 抽 样 总 次 数 , k , 抽 样 为 y = 1 的 次 数 比较Low的写法:L(w)=h_{w}(x_{i})^{k}(1-h_{w}(x_{i}))^{n-k}\qquad n ,抽样总次数,k, 抽样为y=1 的次数 比较Low的写法:L(w)=hw(xi)k(1−hw(xi))n−kn,抽样总次数,k,抽样为y=1的次数
极大似然法估计参数w的核心思想:已知x,y(样本分布),选择w,使得观测的数据(样本分布)出现的概率最大
(个人理解:不同的w,直接导致样本的分布不同,根据已知的分布,选择合适的参数(w),使得对任意样本集的分布 近似为 已知样本集的分布)
参
考
−
−
极
大
似
然
估
计
\href{https://www.cnblogs.com/softlin/p/6219372.html}{参考--极大似然估计}
参考−−极大似然估计
参
考
−
−
极
大
似
然
估
计
\href{https://zhuanlan.zhihu.com/p/26614750}{参考--极大似然估计}
参考−−极大似然估计
w ^ = a r g m a x w L ( w ) \hat{w} = \underset{w}{arg\ max}\ L(w) w^=warg max L(w)
为了简化模型,我们将目标函数转化为:
w
^
=
a
r
g
m
a
x
w
l
n
(
L
(
w
)
)
\hat{w} = \underset{w}{arg\ max}\ ln(L(w))
w^=warg max ln(L(w))对数似然函数(对数函数:积变和,单调递增函数)
l
(
w
)
=
l
n
(
L
(
w
)
)
=
∑
i
=
1
m
y
i
l
n
(
h
w
(
x
i
)
)
+
(
1
−
y
i
)
l
n
(
1
−
h
w
(
x
i
)
)
l(w) = ln(L(w)) = \sum_{i=1}^{m} y_{i}ln(h_{w}(x_{i})) + (1-y_{i})ln(1-h_{w}(x_{i}))
l(w)=ln(L(w))=i=1∑myiln(hw(xi))+(1−yi)ln(1−hw(xi))
梯度下降更新
对于Logistic回归模型,定义其损失函数为:
J
(
w
)
=
−
1
m
∑
i
=
1
m
y
i
l
n
(
h
w
(
x
i
)
)
+
(
1
−
y
i
)
l
n
(
1
−
h
w
(
x
i
)
)
J(w) = -\frac{1}{m} \sum_{i=1}^{m} y_{i}ln(h_{w}(x_{i})) + (1-y_{i})ln(1-h_{w}(x_{i}))
J(w)=−m1i=1∑myiln(hw(xi))+(1−yi)ln(1−hw(xi))
损失函数最小值与对数似然函数最大值等价
计算损失函数梯度:
计
算
J
(
w
)
对
分
量
w
i
的
偏
导
数
计算J(w)对分量w_{i}的偏导数
计算J(w)对分量wi的偏导数
∂
J
(
w
)
∂
w
j
=
−
1
m
∂
∂
w
j
∑
i
=
1
m
y
i
l
n
(
h
w
(
x
i
)
)
+
(
1
−
y
i
)
l
n
(
1
−
h
w
(
x
i
)
)
\frac{\partial J(w)}{\partial w_{j}} = -\frac{1}{m} \frac{\partial }{\partial w_{j}} \sum_{i=1}^{m} y_{i}ln(h_{w}(x_{i})) + (1-y_{i})ln(1-h_{w}(x_{i}))
∂wj∂J(w)=−m1∂wj∂i=1∑myiln(hw(xi))+(1−yi)ln(1−hw(xi))
=
−
1
m
∑
i
=
1
m
y
i
∂
∂
w
j
l
n
(
h
w
(
x
i
)
)
+
(
1
−
y
i
)
∂
∂
w
j
l
n
(
1
−
h
w
(
x
i
)
)
= -\frac{1}{m} \sum_{i=1}^{m} y_{i}\frac{\partial }{\partial w_{j}}ln(h_{w}(x_{i})) + (1-y_{i})\frac{\partial }{\partial w_{j}}ln(1-h_{w}(x_{i}))
=−m1i=1∑myi∂wj∂ln(hw(xi))+(1−yi)∂wj∂ln(1−hw(xi))
=
−
1
m
∑
i
=
1
m
y
i
1
h
w
(
x
i
)
∂
h
w
(
x
i
)
z
i
∂
z
i
w
j
+
(
1
−
y
i
)
1
1
−
h
w
(
x
i
)
−
∂
h
w
(
x
i
)
z
i
∂
z
i
w
j
= -\frac{1}{m} \sum_{i=1}^{m} y_{i}\frac{1}{h_{w}(x_{i})} \frac{\partial h_{w}(x_{i})}{z_{i}} \frac{\partial z_{i}}{w_{j}} + (1-y_{i})\frac{1}{1-h_{w}(x_{i})} \frac{-\partial h_{w}(x_{i})}{z_{i}} \frac{\partial z_{i}}{w_{j}}
=−m1i=1∑myihw(xi)1zi∂hw(xi)wj∂zi+(1−yi)1−hw(xi)1zi−∂hw(xi)wj∂zi
=
−
1
m
∑
i
=
1
m
(
y
i
−
h
w
(
x
i
)
)
∂
z
i
∂
w
j
=-\frac{1}{m} \sum _{i=1}^{m} (y_{i}-h_{w}(x_{i}))\frac{\partial z_{i}}{\partial w_{j}}
=−m1i=1∑m(yi−hw(xi))∂wj∂zi
=
1
m
∑
i
=
1
m
(
h
w
(
x
i
)
−
y
i
)
x
i
=\frac{1}{m} \sum _{i=1}^{m} (h_{w}(x_{i})-y_{i})x_{i}
=m1i=1∑m(hw(xi)−yi)xi
h w ( x i ) − y i 可 解 释 为 模 型 预 测 x i 为 正 例 的 概 率 与 实 际 类 别 之 间 的 误 差 h_{w}(x_{i})-y_{i}可解释为模型预测x_{i}为正例的概率与实际类别之间的误差 hw(xi)−yi可解释为模型预测xi为正例的概率与实际类别之间的误差
对于随机梯度下降算法,相应的梯度计算公式为:
▽ J ( w ) = ( h w ( x i ) − y i ) x i \bigtriangledown J(w) = (h_{w}(x_{i})-y_{i})x_{i} ▽J(w)=(hw(xi)−yi)xi
模 型 参 数 w 的 更 新 公 式 为 : w : = w − η ▽ J ( w ) , η 为 学 习 率 模型参数w的更新公式为:w := w - \eta \bigtriangledown J(w), \eta 为学习率 模型参数w的更新公式为:w:=w−η▽J(w),η为学习率
算法流程:
数据处理
循环
计算内积
概率转换
计算损失
求解梯度
更新参数
判断条件
import numpy as np
class LogisticRegression:
def __init__(self, n_iter=200, eta=1e-3, tol=None):
# 训练迭代次数
self.n_iter = n_iter
#学习率
self.eta = eta
#误差变化阈值
self.tol = tol
#模型参数
self.w = None
def _preprocess_data_X(self, X):
'''数据预处理 '''
m, n = X.shape
X_ = np.empty((m, n+1))
X_[:, 0] = 1
X_[:, 1:] = X
return X_
def _z(self, X, w):
'''g(x)函数,计算内积(x与w)'''
return np.dot(X, w)
def _sigmod(self, z):
'''Logistic函数'''
return 1./(1. + np.exp(-z))
def _predict_proba(self, X, w):
'''h(x)函数,预测y=1的概率'''
z = self._z(X, w)
return self._sigmod(z)
def _loss(self, y, y_proba):
'''计算损失'''
m = y.size
p = y_proba * (2 * y - 1) + (1 - y)
return -np.sum(np.log(p)) / m
def _gradient(self, X, y, y_proba):
'''计算梯度'''
return np.matmul(y_proba-y, X) / y.size
def _gradient_descent(self, w, X, y):
'''梯度下降算法'''
if self.tol is not None:
loss_old = np.inf
for step_i in range(self.n_iter):
y_proba = self._predict_proba(X, w)
loss = self._loss(y, y_proba)
print('%4i Loss: %s' % (step_i, loss))
if self.tol is not None:
if loss_old - loss < self.tol:
break
loss_old = loss
grad = self._gradient(X, y, y_proba)
w -= self.eta * grad
def train(self, X_train, y_train):
'''训练'''
#预处理
X_train = self._preprocess_data_X(X_train)
#初始化参数向量
_, n = X_train.shape
self.w = np.random.random(n) * 0.5
#梯度下降训练
self._gradient_descent(self.w, X_train, y_train)
def predict(self, X):
'''预测'''
X = self._preprocess_data_X(X)
y_pred = self._predict_proba(X, self.w)
# p>0.5 y=1
return np.where(y_pred >= 0.5, 1, 0)
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# 数据导入
X = np.genfromtxt('wine.data', delimiter=',', usecols=range(1, 14))
y = np.genfromtxt('wine.data', delimiter=',', usecols=0)
idx = (y != 3)
X = X[idx]
y = y[idx]
y -= 1
#划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
#标准化
ss = StandardScaler()
ss.fit(X_train)
StandardScaler(copy=True, with_mean=True, with_std=True)
X_train_std = ss.transform(X_train)
X_test_std = ss.transform(X_test)
# 模型处理
clf = LogisticRegression(n_iter=2000, eta=0.01, tol=0.0001)
clf.train(X_train_std, y_train)
# 模型检验
from sklearn.metrics import accuracy_score
y_pred = clf.predict(X_test_std)
accuracy = accuracy_score(y_test, y_pred)
accuracy
0.9743589743589743
Softmax回归
Logistic回归只能处理二元分类问题,在此基础上推广得到的Sotfmax回归可以处理多元分类问题。Sotfmax回归也被称为多元Logistic回归。
Sotfmax函数
假设有k个分类,Sotfmax对实例x的类别进行预测时,需分别计算x属于每一个类别的概率,因此每个类别拥有各自独立的线性函数:
z
j
=
g
j
(
x
)
=
w
j
T
x
z_{j} = g_{j}(x) = w_{j}^{T}x
zj=gj(x)=wjTx
W = [ w 1 T w 2 T ⋮ w k T ] W=\begin{bmatrix} w_{1}^{T}\\ w_{2}^{T} \\ \vdots \\ w_{k}^{T}\\ \end{bmatrix} W=⎣⎢⎢⎢⎡w1Tw2T⋮wkT⎦⎥⎥⎥⎤
定
义
S
o
t
f
m
a
x
回
归
的
g
(
x
)
函
数
为
:
定义Sotfmax回归的g(x)函数为:
定义Sotfmax回归的g(x)函数为:
z
=
g
(
x
)
=
W
x
=
[
z
1
z
2
⋮
z
k
]
z = g(x) = Wx = \begin{bmatrix} z_{1}\\ z_{2} \\ \vdots \\ z_{k}\\ \end{bmatrix}
z=g(x)=Wx=⎣⎢⎢⎢⎡z1z2⋮zk⎦⎥⎥⎥⎤
定义Softmax函数为:
σ
(
z
)
j
=
e
z
j
∑
k
=
1
K
e
z
k
\sigma (z)_{j} = \frac{e^{z_{j}}}{\sum_{k=1}^{K} e^{z_{k}}}
σ(z)j=∑k=1Kezkezj
Softmax函数的输出为:
σ
(
z
)
=
[
σ
(
z
)
1
σ
(
z
)
2
⋮
σ
(
z
)
k
]
\sigma (z) = \begin{bmatrix} \sigma (z)_{1}\\ \sigma (z)_{2}\\ \vdots \\ \sigma (z)_{k} \end{bmatrix}
σ(z)=⎣⎢⎢⎢⎡σ(z)1σ(z)2⋮σ(z)k⎦⎥⎥⎥⎤
Sotfmax回归模型假设函数为:
h
w
(
x
)
=
σ
(
g
(
x
)
)
=
1
∑
k
=
1
K
e
w
k
T
x
[
e
w
1
T
x
e
w
2
T
x
⋮
e
w
K
T
x
]
h_{w}(x) = \sigma(g(x)) = \frac {1}{\sum_{k=1}^{K}e^{w_{k}^{T}x}}\begin{bmatrix} e^{w_{1}^{T}x}\\ e^{w_{2}^{T}x}\\ \vdots \\ e^{w_{K}^{T}x} \end{bmatrix}
hw(x)=σ(g(x))=∑k=1KewkTx1⎣⎢⎢⎢⎢⎡ew1Txew2Tx⋮ewKTx⎦⎥⎥⎥⎥⎤
Sotfmax函数的输出是预测x为各类别的概率,通过训练确定了模型参数W,便可构建多元分类函数:
H
(
h
w
(
x
)
)
=
a
r
g
m
a
x
k
h
W
(
x
)
k
=
a
r
g
m
a
x
k
(
W
k
T
x
)
H(h_{w}(x)) = \underset{k}{arg \ max} \ h_{W}(x)_{k} = \underset{k}{arg \ max}({W}_{k}^{T}x)
H(hw(x))=karg max hW(x)k=karg max(WkTx)
梯度下降更新公式
Sotfmax回归模型的损失函数为:
J
(
w
)
=
−
1
m
∑
i
=
1
m
∑
j
=
1
K
I
(
y
i
=
j
)
l
n
h
W
(
x
i
)
J(w) = -\frac{1}{m} \sum_{i=1}^{m} \sum_{j=1}^{K} I(y_{i}=j)ln\ h_{W}(x_{i})
J(w)=−m1i=1∑mj=1∑KI(yi=j)ln hW(xi)
I 为 指 示 函 数 , 当 y i = j 时 , I = 1 , 否 则 I = 0 I为指示函数,当y_{i}= j时,I=1,否则I=0 I为指示函数,当yi=j时,I=1,否则I=0
这里直接给出梯度的计算公式:
▽
w
j
J
(
W
)
=
1
m
∑
i
=
1
m
(
h
W
(
x
i
)
j
−
I
(
y
i
=
j
)
)
x
i
\bigtriangledown _{w_{j}}J(W) = \frac{1}{m} \sum _{i=1}^{m}(h_{W}(x_{i})_{j}-I(y_{i}=j))x_{i}
▽wjJ(W)=m1i=1∑m(hW(xi)j−I(yi=j))xi
h W ( x i ) j − I ( y i = j ) 可 以 解 释 为 模 型 预 测 x i 为 第 j 类 别 的 概 率 与 其 是 否 为 第 j 类 别 之 间 的 误 差 h_{W}(x_{i})_{j}-I(y_{i}=j)可以解释为模型预测x_{i}为第j类别的概率与其是否为第j类别之间的误差 hW(xi)j−I(yi=j)可以解释为模型预测xi为第j类别的概率与其是否为第j类别之间的误差
对于随机梯度下降算法,每次只使用一个样本来计算梯度,相应梯度计算公式为:
▽
w
j
J
(
W
)
=
∑
i
=
1
m
(
h
W
(
x
i
)
j
−
I
(
y
i
=
j
)
)
x
i
\bigtriangledown _{w_{j}}J(W) = \sum _{i=1}^{m}(h_{W}(x_{i})_{j}-I(y_{i}=j))x_{i}
▽wjJ(W)=i=1∑m(hW(xi)j−I(yi=j))xi
w
j
的
更
新
公
式
为
:
w
j
:
=
w
j
−
η
▽
w
j
J
(
W
)
w_{j}的更新公式为:w_{j}:=w_{j}-\eta \bigtriangledown _{w_{j}}J(W)
wj的更新公式为:wj:=wj−η▽wjJ(W)
即:
W
:
=
W
−
η
[
▽
w
1
J
(
w
)
T
▽
w
2
J
(
w
)
T
⋮
▽
w
k
J
(
w
)
T
]
W:=W-\eta \begin{bmatrix} \bigtriangledown _{w_{1}}J(w)^{T}\\ \bigtriangledown _{w_{2}}J(w)^{T}\\ \vdots\\ \bigtriangledown _{w_{k}}J(w)^{T}\\ \end{bmatrix}
W:=W−η⎣⎢⎢⎢⎡▽w1J(w)T▽w2J(w)T⋮▽wkJ(w)T⎦⎥⎥⎥⎤
import numpy as np
import random
class SoftmaxRegression:
def __init__(self, n_iter=200, eta=1e-3, tol=None):
# 训练迭代次数
self.n_iter = n_iter
# 学习率
self.eta = eta
# 误差变化阈值
self.tol = tol
# 模型参数W
self.W = None
def _z(self, X, W):
'''g(x)函数:计算X与W内积'''
if X.ndim == 1 :
return np.dot(W, X)
return np.matmul(X, W.T)
def _softmax(self, Z):
'''softmax函数'''
E = np.exp(Z)
if Z.ndim == 1:
return E / np.sum(E)
return E / np.sum(E, axis=1, keepdims=True)
def _predict_proba(self, X, W):
'''h(x)函数,预测y为各类别的概率'''
Z = self._z(X, W)
return self._softmax(Z)
def _loss(self, y, y_proba):
'''计算损失'''
m = y.size
# 获取每个样本对应种类的概率,如果这个样本为1类,就选取其对应1类的概率
p = y_proba[range(m), y]
return -np.sum(np.log(p)) / m
def _gradient(self, xi, yi, yi_proba):
'''计算梯度'''
K = yi_proba.size
y_bin = np.zeros(K)
# 对应样本类型为1
y_bin[yi] = 1
return (yi_proba - y_bin)[:,None] * xi
def _stochastic_gradient_descent(self, W, X, y):
'''随机梯度下降算法'''
if self.tol is not None:
loss_old = np.inf
end_count = 0
# 核心代码
m = y.size
idx = np.arange(m)
for step_i in range(self.n_iter):
# 计算损失
y_proba = self._predict_proba(X, W)
loss = self._loss(y, y_proba)
print('%4i Loss: %s '%(step_i, loss))
if self.tol is not None:
# 随机梯度下降的loss曲线起伏较大,连续多次低于阈值,停止算法
if loss_old - loss < self.tol:
end_count += 1
if end_count == 5:
break
else:
end_count = 0
loss_old = loss
# 每一轮迭代前,打乱数据集
np.random.shuffle(idx)
for i in idx:
yi_proba = self._predict_proba(X[i], W)
grad = self._gradient(X[i], y[i], yi_proba)
# 根据每一个样本更新梯度
W -= self.eta * grad
def _preprocess_data_X(self, X):
m, n = X.shape
X_ = np.empty((m, n+1))
X_[:, 0] = 1
X_[:, 1:] = X
return X_
def train(self, X_train, y_train):
X_train = self._preprocess_data_X(X_train)
k = np.unique(y_train).size
_, n = X_train.shape
self.W = np.random.random((k, n)) * 0.05
self._stochastic_gradient_descent(self.W, X_train, y_train)
def predict(self, X):
X = self._preprocess_data_X(X)
Z = self._z(X, self.W)
return np.argmax(Z, axis=1)
X = np.genfromtxt('wine.data', delimiter=',', usecols=range(1, 14))
y = np.genfromtxt('wine.data', delimiter=',', usecols=0)
y -= 1
y=y.astype(np.int32)
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
ss = StandardScaler()
ss.fit(X_train)
StandardScaler(copy=True, with_std=True, with_mean=True)
X_train_std = ss.transform(X_train)
X_test_std = ss.transform(X_test)
clf = SoftmaxRegression(n_iter=2000, eta=0.01, tol=0.0001)
clf.train(X_train_std, y_train)
# 模型检验
from sklearn.metrics import accuracy_score
y_pred = clf.predict(X_test_std)
accuracy_score(y_test, y_pred)
Python机器学习算法:原理,实现与案例 – 刘硕