最优化方法Python计算:无约束优化应用——线性回归分类器
一、线性回归分类器
假设样本数据为 ( x i , y i ) (\boldsymbol{x}_i, y_i) (xi,yi),其中 i = 1 , 2 , … , m i = 1, 2, \dots, m i=1,2,…,m。标签 y i y_i yi 取值于 k k k 个整数 { 1 , 2 , … , k } \{1, 2, \dots, k\} {1,2,…,k},从而构成一个 k k k-分类问题。线性回归分类器与线性回归预测器的测试评估指标不同,当我们用训练数据得到模型参数 w 0 \boldsymbol{w}_0 w0 后,可以利用测试数据集评估模型性能。设测试数据集为 { ( x i , y i ) ∣ i = 1 , 2 , ⋯ , m } \{(\boldsymbol{x}_i, y_i)|i=1,2,\cdots,m\} {(xi,yi)∣i=1,2,⋯,m},其中 x i \boldsymbol{x}_i xi 为特征向量, y i y_i yi 为真实标签。定义测试数据矩阵:
X t e s t = ( x 1 ⊤ 1 x 2 ⊤ 1 ⋮ ⋮ x m ⊤ 1 ) , Y t e s t = ( y 1 y 2 ⋮ y m ) , \boldsymbol{X}_{test} = \begin{pmatrix} \boldsymbol{x}_1^\top & 1 \\ \boldsymbol{x}_2^\top & 1 \\ \vdots & \vdots \\ \boldsymbol{x}_m^\top & 1 \end{pmatrix}, \quad \boldsymbol{Y}_{test} = \begin{pmatrix} y_1 \\ y_2 \\ \vdots \\ y_m \end{pmatrix}, Xtest= x1⊤x2⊤⋮xm⊤11⋮1 ,Ytest= y1y2⋮ym ,
其中, X t e s t \boldsymbol{X}_{test} Xtest 的最后一列全为 1,用于引入偏置项。用线性回归方法计算预测值:
( y 1 ′ y 2 ′ ⋮ y m ′ ) = Y ′ = round ( X t e s t w 0 ) . \begin{pmatrix} y_1' \\ y_2' \\ \vdots \\ y_m' \end{pmatrix} = \boldsymbol{Y}' = \text{round}(\boldsymbol{X}_{test} \boldsymbol{w}_0). y1′y2′⋮ym′ =Y′=round(Xtestw0).
其中, round ( ⋅ ) \text{round}(\cdot) round(⋅) 表示逐元素取整操作。
设 m ′ m' m′ 为 Y t e s t \boldsymbol{Y}_{test} Ytest与 Y ′ \boldsymbol{Y}' Y′中 y i = y i ′ y_i=y_i' yi=yi′, i = 1 , 2 , ⋯ , m i=1,2,\cdots,m i=1,2,⋯,m的个数(即预测值与真实标签值相等的样本数),则测试评估指标定义为准确率:
score = m ′ m × 100 % . \text{score}=\frac{m'}{m}\times100\%{}. score=mm′×100%.
其中, m m m 为测试样本总数。准确率反映了模型预测正确的比例。下列代码实现线性回归分类器。
import numpy as np
class Classification(): #分类模型def score(self, x, y): #测试函数return np.mean(self.predict(x) == y)
class LinearClassifier(Classification,LineModel): #线性分类模型def __init__(self):self.tagVal=np.round
程序中
- 第2~4行定义了用于表示分类模型的Classification。其中,第3~4行定义了分类器的测试函数score。第4行调用predict函数对表示特征数据的参数x计算预测值并于表示标签数据的参数y比较,算得相等即预测正确的均值,计算正确率并返回。
- 第5~7行将线性分类模型类LinearClassifier定义成Classification和LineModel(见博文《最优化方法Python计算:无约束优化应用——线性回归模型》)的子类。该类拥有其两个父类Classification和LineModel的所有数据和方法。其中,第6~7行定义的构造函数将tagVal函数设置为Numpy的舍入函数round,使得预测值
self.tagVal(yp * (self.ymax - self.ymin) + self.ymin) \text{self.tagVal(yp * (self.ymax - self.ymin) + self.ymin)} self.tagVal(yp * (self.ymax - self.ymin) + self.ymin)
(见博文《最优化方法Python计算:无约束优化应用——线性回归模型》中predict函数的定义)
二、综合案例
文件iris.csv(来自UC Irvine Machine Learning Repository)是统计学家R. A. Fisher在1936年采集的一个小型经典数据集,这是用于评估分类方法的最早的已知数据集之一。该数据集含有150例3种鸢尾花:setosa、versicolour和virginica的数据
Sepal.Length | Sepal.Width | Petal.Length | Petal.Width | Species | |
---|---|---|---|---|---|
1 | 5.1 | 3.5 | 1.4 | 0.2 | setosa |
2 | 4.9 | 3 | 1.4 | 0.2 | setosa |
3 | 4.7 | 3.2 | 1.3 | 0.2 | setosa |
⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ |
51 | 7 | 3.2 | 4.7 | 1.4 | versicolor |
52 | 6.4 | 3.2 | 4.5 | 1.5 | versicolor |
53 | 6.9 | 3.1 | 4.9 | 1.5 | versicolor |
⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ |
148 | 6.5 | 3 | 5.2 | 2 | virginica |
149 | 6.2 | 3.4 | 5.4 | 2.3 | virginica |
150 | 5.9 | 3 | 5.1 | 1.8 | virginica |
五个数据属性的意义分别为
- Sepal.Length:花萼长度;
- Sepal.Width:花萼宽度;
- Petal.Length:花瓣长度;
- Petal.Width:花瓣宽度;
- Species:种类。
下列代码从文件中读取数据,将花的种类数字化。
import numpy as np #导入numpy
data = np.loadtxt('iris.csv', delimiter=',', dtype=str) #读取数据文件
X = np.array(data) #转换为数组
X = X[:, 1:] #去掉编号
title = X[0, :4] #读取特征名称
X = X[1:, :] #去掉表头
Y = X[:, 4] #读取标签数据
X = X[:, :4].astype(float)
m = X.shape[0] #读取样本个数
print('共有%d个数据样本'%m)
print('鸢尾花特征数据:')
print(X)
Y = np.array([0 if y == 'setosa' else #类别数值化1 if y == 'versicolor' else2 for y in Y])
print('鸢尾花种类数据:')
print(Y)
运行程序,输出
共有150个数据样本
鸢尾花特征数据:
[[5.1 3.5 1.4 0.2][4.9 3. 1.4 0.2][4.7 3.2 1.3 0.2]
...[6.5 3. 5.2 2. ][6.2 3.4 5.4 2.3][5.9 3. 5.1 1.8]]
鸢尾花种类数据:
[0 0 0 ... 2 2 2]
花萼的长度、宽度,花瓣的长度、宽度对鸢尾花的种类有明显的相关性。接下来我们要从数据集中随机选取一部分作为训练数据,训练LinearRegressor分类模型,然后用剩下的数据进行测试,评价训练效果。在前面的程序后添加以下代码
……
a = np.arange(m) #数据项下标
np.random.seed(1248)
train = np.random.choice(a,m//3,replace=False) #50个随机下标
test = np.setdiff1d(a,train) #测试数据下标
iris = LinearRegressor() #创建模型
print('随机抽取%d个样本作为训练数据。'%(m//3))
iris.fit(X[train],Y[train]) #训练模型
accuracy = iris.score(X[test],Y[test]) #测试
print('对其余%d个数据测试,分类正确率为%.2f'%(m-m//3,accuracy)+'%')
运行程序输出
………
随机抽取50个样本作为训练数据。
训练中...,稍候
9次迭代后完成训练。
对其余100个数据测试,分类正确率为100.00%
第1行的省略号表示前一程序的输出。从测试结果可见训练效果效果不错!
写博不易,敬请支持:
如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!