最优化方法Python计算:无约束优化应用——逻辑分类模型

逻辑回归模型更多地用于如下例所示判断或分类场景。
例1 某银行的贷款用户数据如下表:

欠款(元) 收入(元) 是否逾期
1 7000 800 Yes
2 2000 2500 No
3 5000 3000 Yes
4 4000 4000 No
5 2000 3800 No

显然,客户是否逾期(记为 y y y)与其欠款额(记为 x 1 x_1 x1)和收入(记为 x 2 x_2 x2)相关。如果将客户逾期还款记为1,未逾期记为0,我们希望根据表中数据建立 R 2 → { 0 , 1 } \text{R}^2\rightarrow\{0,1\} R2{0,1}的拟合函数
y = F ( x ) y=F(\boldsymbol{x}) y=F(x)
使得 F ( x i ) ≈ y i , i = 1 , 2 , ⋯   , 5 F(\boldsymbol{x}_i)\approx y_i,i=1,2,\cdots,5 F(xi)yi,i=1,2,,5,并用 F ( x ) F(\boldsymbol{x}) F(x)根据新客户的欠款额与收入数据

欠款(元) 收入(元) 是否逾期
3500 3500 ?
3000 2100 ?

进行预测分类。
要用回归模型分类,关键在于如何将预测值 y y y离散化为0,1,或一般地离散化为连续的 n n n个整数 N 1 , N 1 + 1 , ⋯   , N 1 + n − 1 , N 2 N_1, N_1+1,\cdots,N_1+n-1,N_2 N1,N1+1,,N1+n1,N2。解决之道是设置阈值,譬如,设 μ 1 = N 1 + 0.5 , μ 2 = N 1 + 1.5 , ⋯   , μ n − 1 = N 1 + n − 0.5 \mu_1=N_1+0.5,\mu_2=N_1+1.5,\cdots,\mu_{n-1}=N_1+n-0.5 μ1=N1+0.5,μ2=N1+1.5,,μn1=N1+n0.5,对 y < μ 1 y<\mu_1 y<μ1 y y y转换为 N 1 N_1 N1 μ i ≤ y < μ i + 1 \mu_i\leq y<\mu_{i+1} μiy<μi+1,将其转化为 N 1 + i N_1+i N1+i y ≥ μ n − 1 y\geq\mu_{n-1} yμn1,转换为 N 2 N_2 N2
其次,对分类模型的评价指标应该是分类正确率:设 ( x i , y i ) (\boldsymbol{x}_i,y_i) (xi,yi) i = 1 , 2 , ⋯   , m i=1,2,\cdots,m i=1,2,,m为测试数据。用训练所得的最优模式 w 0 \boldsymbol{w}_0 w0,得预测值 y i ′ y'_i yi i = 1 , 2 , ⋯   , m i=1,2,\cdots,m i=1,2,,m。记 y = ( y 1 y 2 ⋮ y m ) \boldsymbol{y}=\begin{pmatrix}y_1\\y_2\\\vdots\\y_m\end{pmatrix} y= y1y2ym y t = ( y 1 ′ y 2 ′ ⋮ y m ′ ) \boldsymbol{y}_t=\begin{pmatrix}y'_1\\y'_2\\\vdots\\y'_m\end{pmatrix} yt= y1y2ym ,计算 y i = y i ′ y_i=y'_i yi=yi成立的个数 m 1 m_1 m1,则正确率为 m 1 m × 100 \frac{m_1}{m}\times100 mm1×100
下列代码实现用于分类的Classification类。

import numpy as np										#导入numpy
class Classification():									#分类模型
    def threshold(self, x):								#阈值函数
        N1 = x.min().astype(int) - 1					#最小阈值整数部分
        N2 = np.round(x.max()).astype(int) + 1			#最大阈值整数部分
        y = np.array([N1] * x.size)						#因变量数组
        for n in range(N1, N2):							#对每个可能的函数值
            d = np.where((x >= n - 0.5)&(x < n + 0.5))	#取值区间
            y[d] = n									#函数值
        if(y.size == 1):								#单值情形
            y = y[0]
        return y
    def predict(self, X):								#重载预测函数
        yp = RegressModel.predict(self, X)				#计算预测值
        return self.threshold(yp)						#转换为离散值
    def accuracy(self, y1, y2):							#正确率
        m = y1.size
        acc=np.where(y1 == y2)[0].size					#计算两者相等的元素个数
        return acc / m * 100
    def test(self, x, y):								#测试函数
        yp = self.predict(x)
        return yp, self.accuracy(y, yp)
class LogicClassifier(Classification, LogicModel):
    '''逻辑分类模型'''

程序中第2~22行定义了用于分类的Classification辅助类。其中第3~12行定义阈值函数threshold。第13~15行在预测函数predict外“套上”阈值函数threshold,筛选出分类值返回。第16~19行定义计算两个等长整数数组y1,y2中对应元素相等的比率函数accuracy。第20~22行定义测试函数test,对测试数据x和y,计算x的预测值yp,然后调用accuracy计算y和yt的相等比率返回。第23~24行联合Classification类和LogicModel类(详见博文《最优化方法Python计算:无约束优化应用——逻辑回归模型》)实现逻辑分类模型类LogicClassifier。下面我们来小试牛刀:用逻辑分类模型LogicClassifier计算例1中的问题。

import numpy as np								#导入numpy
x = np.array([[7000, 800],						#设置训练、测试数据
              [2000, 2500],
              [5000, 3000],
              [4000, 4000],
              [2000, 3800]])
y = np.array([1, 0, 1, 0, 0])
title = np.array(['No', 'Yes'])					#预测值标签
np.random.seed(2024)							#随机种子
credit = LogicClassifier()						#创建逻辑分类模型
credit.fit(x,y)									#训练
_, acc=credit.test(x,y)							#测试
print('准确率:%.1f'%acc + '%')
x1 = np.array([[3500, 3500],					#设置预测数据
               [3000, 2100]])
print('对测试数据:')
print(x1)
Y = credit.predict(x1)							#计算预测值
print('归类为:')
print([title[y] for y in Y])

看官可借助代码内注释信息理解程序,需要提请注意的是第9行设置随机种子是为了使看官的运行结果与下列的输出一致。运行程序,输出

训练中...,稍候
3次迭代后完成训练。
准确率:100.0%
对测试数据:
[[3500 3500]
 [3000 2100]]
归类为:
['No', 'Yes']

开胃菜后,上正餐。
综合案例
文件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' else
              2 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]

花萼的长度、宽度,花瓣的长度、宽度对鸢尾花的种类有明显的相关性。接下来我们要从数据集中随机选取一部分作为训练数据,训练LogicClassifier分类模型,然后用剩下的数据进行测试,评价训练效果。在前面的程序后添加以下代码

……
a = np.arange(m)									#数据项下标
np.random.seed(2024)
index = np.random.choice(a,m//3,replace=False)		#50个随机下标
Xtrain = X[index]									#训练数据
Ytrain = Y[index]
index1 = np.setdiff1d(a,index)						#测试数据下标
Xtest = X[index1]									#测试数据
Ytest = Y[index1]
iris = LogicClassifier()							#创建模型
print('随机抽取%d个样本作为训练数据。'%(m//3))
iris.fit(Xtrain,Ytrain)								#训练模型
_, accuracy = iris.test(Xtest,Ytest)				#测试
print('对其余%d个数据测试,分类正确率为%.2f'%(m-m//3,accuracy)+'%')

运行程序输出

随机抽取50个样本作为训练数据。
训练中...,稍候
23次迭代后完成训练。
对其余100个数据测试,分类正确率为99.00%

效果不错!

你可能感兴趣的:(最优化方法,python,分类,机器学习,最优化方法)