- 概述:
- Logistic回归
- 线性分类器
- logistic函数
- 概率意义
- 对数概率函数
- 一阶导数
- Logistic回归模型
- 极大似然法估计参数
- 梯度下降更新
- Softmax回归
- Sotfmax函数
- 梯度下降更新公式
——《 Python机器学习算法:原理,实现与案例》读书笔记
相关数据集:
链接:https://pan.baidu.com/s/1fBNk7mbqCczKawmOyk491Q
提取码:niz2
Logistic回归虽然名为回归,实为分类算法,用于处理二分类问题
Sotfmax回归是在Logistic回归的基础上推广得到的,用于处理多元分类问题
线性分类器
先从简单的二维平面的二分类问题开始
如下图所示:
在二维平面内存在两种类别的样本,我们可以找到一条直线,将这两种样本尽可能好得划分开
假
设
直
线
方
程
为
:
假设直线方程为:
假设直线方程为:
w
T
x
+
b
=
0
w
,
b
∈
R
w^{T}x+b=0 qquad w,bin R
wTx+b=0w,b∈R
直
线
上
方
的
点
都
满
足
:
w
T
x
+
b
>
k
直线上方的点都满足:w^{T}x+b>k
直线上方的点都满足:wTx+b>k 这意味着,我们可以根据找出的这条直线,判断样本的类别 对于多维空间的分类问题,类似上述问题,我们只需要找到一个超平面,可以将所有样本尽可能好得划分开(类似SVM)
假
设
超
平
面
方
程
为
:
假设超平面方程为:
假设超平面方程为: 对于二维平面的二分类问题,最理想的分类函数显然为单位阶跃函数: logistic是一种sigmoid函数,其值域在(0,1)之间连续 在统计学中,几率(odds) 定义为:事件发生的概率与事件不发生概率的比值 对数几率: 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
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回归模型假设函数为: 通常将b作为w0纳入权向量w,同时为输入向量添加常数1作为x0:
h
w
(
x
)
的
输
出
为
预
测
x
为
正
例
的
概
率
,
通
过
训
练
可
以
确
定
模
型
参
数
w
,
构
建
二
元
分
类
函
数
:
h_{w}(x)的输出为 预测x 为正例的概率,通过训练可以确定模型参数w,构建二元分类函数:
hw(x)的输出为预测x为正例的概率,通过训练可以确定模型参数w,构建二元分类函数: 对于给定的包含m个样本的数据集D,可以使用极大似然法估计w
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
^
=
a
r
g
m
a
x
w
L
(
w
)
hat{w} = underset{w}{arg max} L(w)
w^=warg max L(w) 为了简化模型,我们将目标函数转化为: 对于Logistic回归模型,定义其损失函数为: 计算损失函数梯度:
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),η为学习率 算法流程: 数据处理 循环 判断条件 Logistic回归只能处理二元分类问题,在此基础上推广得到的Sotfmax回归可以处理多元分类问题。Sotfmax回归也被称为多元Logistic回归。 假设有k个分类,Sotfmax对实例x的类别进行预测时,需分别计算x属于每一个类别的概率,因此每个类别拥有各自独立的线性函数:
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)函数为: 定义Softmax函数为: Sotfmax回归模型假设函数为: Sotfmax函数的输出是预测x为各类别的概率,通过训练确定了模型参数W,便可构建多元分类函数: Sotfmax回归模型的损失函数为:
I
为
指
示
函
数
,
当
y
i
=
j
时
,
I
=
1
,
否
则
I
=
0
I为指示函数,当y_{i}= j时,I=1,否则I=0
I为指示函数,当yi=j时,I=1,否则I=0 这里直接给出梯度的计算公式:
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
的
更
新
公
式
为
:
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) Python机器学习算法:原理,实现与案例 – 刘硕
而
直
线
下
方
的
点
都
满
足
:
w
T
x
+
b
<
k
其
中
k
为
常
数
而直线下方的点都满足:w^{T}x+b
设
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=
w
T
x
+
b
=
0
w
∈
R
n
,
b
∈
R
w^{T}x+b=0 qquad win R^{n},bin R
wTx+b=0w∈Rn,b∈R
类似的,根据此函数的输出函数值,我们可以实现对样本的分类
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
函数的输出可以视为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
几率表示的是样本作为正例的相对可能性
l
o
g
p
1
−
p
log frac{p}{1-p}
log1−pp对数几率大于0表明正例的概率大,大于0表明负例的概率大
反求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
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
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
(
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
易
知
,
模
型
将
输
入
实
例
x
i
预
测
为
y
i
的
概
率
为
:
易知,模型将输入实例x_{i}预测为y_{i}的概率为:
易知,模型将输入实例xi预测为yi的概率为:
(个人理解:不同的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
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))
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计算内积
概率转换
计算损失
求解梯度
更新参数
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回归
z
j
=
g
j
(
x
)
=
w
j
T
x
z_{j} = g_{j}(x) = w_{j}^{T}x
zj=gj(x)=wjTx
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⎦⎥⎥⎥⎤
σ
(
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⎦⎥⎥⎥⎤
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⎦⎥⎥⎥⎥⎤
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)
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)
▽
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
▽
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
:
=
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)



