利用线性Lasso模型类LineLassoModel类(见博文《最优化方法Python计算:有约束优化应用——线性Lasso回归预测器》)及分类器类Classification(见博文《最优化方法Python计算:无约束优化应用——线性回归分类器》),下列代码实现线性Lasso分类器。
class LassoClassifier(Classification, LineLassoModel): #线性Lasso分类器def __init__(self, alpha = 1.0):self.alpha = alphaself.tagVal = np.round
第1~4行用LineLassoModel和Classification类实现线性Lasso分类器类LassoClassifier。第2~4行的构造函数初始化正则化系数alpha,将标签值函数tagVal设置为四舍五入函数numpy.round,以适于分类预测。
综合案例
文件heart_failure_clinical_records_dataset.csv(来自UC Irvine Machine Learning Repository)记录了299例心力衰竭病人的数据。
age | anaemia | ⋯ \cdots ⋯ | diabetes | $cdots$ | ⋯ \cdots ⋯ | platelets | sex | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | smoking | time | DEATH_EVENT |
---|---|---|---|---|---|---|---|---|---|---|---|---|
75 | 0 | ⋯ \cdots ⋯ | 0 | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | 265000 | 1.9 | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | 0 | 4 | 1 |
⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ |
70 | 0 | ⋯ \cdots ⋯ | 0 | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | 244000 | 1.2 | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | 0 | 66 | 1 |
⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ |
60 | 1 | ⋯ \cdots ⋯ | 0 | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | 210000 | 1.7 | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | 0 | 82 | 1 |
⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ |
55 | 0 | ⋯ \cdots ⋯ | 0 | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | 263358.03 | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | 1 | 1 | 241 | 1 |
⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ |
50 | 0 | ⋯ \cdots ⋯ | 0 | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | 395000 | 1.6 | ⋯ \cdots ⋯ | ⋯ \cdots ⋯ | 1 | 285 | 0 |
其中,
- age - 患者的年龄(年)
- anaemia - 患者是否贫血(布尔值)
- creatinine phosphokinase(CPK) - 血液中CPK酶的水平(mcg/L)
- diabetes - 患者是否患有糖尿病(布尔值)
- ejection fraction - 每次收缩时离开心脏的血液百分比(百分比)
- high blood pressure - 患者是否患有高血压(布尔值)
- platelets - 血液中的血小板(kiloplatelets/mL)
- sex - 性别(二进制)
- serum creatinine - 血液中的血清肌酐水平(毫克/分升)
- serum sodium - 血液中的血清钠水平(mEq/L)
- smoking - 患者是否吸烟(布尔值)
- time - 随访期(天数)
- DEATH_EVENT - 患者是否在随访期间死亡(布尔值)
将表示患者是否死亡的\texttt{DEATH_EVENT}作为标签数据,其余12个数据项作为特征数据,则判断患者是否会在就医时死亡构成一个2-分类问题。下列代码用这一数据集训练测试一个线性分类LinearClassifier(见博文《最优化方法Python计算:无约束优化应用——线性回归分类器》)模型。
import numpy as np #导入numpy
LassoClassifier,LinearClassifier
np.set_printoptions(precision=4)
data = np.loadtxt('heart_failure_clinical_records_dataset.csv', delimiter=',', dtype=object, skiprows=1) #读取数据文件
X = np.array(data) #转换为数组
Y = X[:, 12].astype(int) #读取标签数据
X = np.delete(X, [12], axis = 1).astype(float) #特征数据
m, n = X.shape
print('共有%d个数据样本'%m)
a=np.arange(m) #样本下标集
np.random.seed(1766) #随机种子
print('随机抽取%d个样本作为训练数据。'%(m // 2))
train = np.random.choice(a, m // 2, replace = False) #随机取得一半作为训练集下标
test = np.setdiff1d(a, train) #测试集下标
print('LINE REGRESSION:')
heart_failure = LinearClassifier() #构造线性回归模型
heart_failure.fit(X[train], Y[train]) #训练模型
coef, inte = heart_failure.coef_inte() #模型的系数和截距
print('系数:', coef)
print('截距:%.4f'%inte)
acc = heart_failure.score(X[test], Y[test]) * 100 #测试模型
print('对其余%d个样本数据测试,准确率:%.4f'%(m - m // 2, acc) + '%')
程序的第3~8行读取文件数据并将其分离成样本特征数据X和标签数据Y。第11~14行在数据集中随机选取一般作为训练数据,下标为train,另一半作为测试数据,下标为test。第16行用LinearClassifier类创建一个线性分类模型heart_failure。第17行调用heart_failure的fit函数用X[train]和Y[train]训练heart_failure。第18行调用heart_failure的coef_inte函数计算系数和截距。第21行调用heart_failure的score函数用X[test]和Y[test]测试heart_failure。运行程序,输出
共有299个数据样本
随机抽取149个样本作为训练数据。
LINE REGRESSION:
训练中...,稍候
17次迭代后完成训练。
系数: [ 6.1401e-03 -2.1315e-02 4.1355e-05 -1.0871e-02 -9.2742e-03 -2.2379e-02-1.8753e-07 7.4815e-02 -9.0710e-03 -1.5951e-01 3.4964e-02 -2.5166e-03]
截距:1.9301
对其余150个样本数据测试,准确率:90.6667%
即经17次迭代,用X[train]和Y[train]训练了线性分类模型。用X[test]和Y[test]测试该模型得到90.667%的正确率。接下来我们分别用X[train]、Y[train]和X[test]、Y[test]训练和测试一个线性Lasso分类器LassoClassifier模型。前一程序之后添加下列代码
……
print('LASSO REGRESSION:')
heart_failure = LassoClassifier(alpha = 0.5) #构造Lasso分类模型
heart_failure.fit(X[train], Y[train]) #训练模型
coef, inte = heart_failure.coef_inte()
print('系数:',coef)
print('截距:%.4f'%inte)
acc = heart_failure.score(X[test], Y[test]) * 100 #测试模型
print('对其余%d个样本数据测试,准确率:%.4f'%(m - m // 2, acc) + '%')
程序第1行的省略号表示前一程序的代码。第3行将heart_failure声明为LassoClassifier类对象,传递给构造函数的参数alpha为0.5。第4行用X[train]、Y[train]训练heart_failure。第8行用X[test]、Y[test]测试heart_failure。运行程序,输出
LASSO REGRESSION:
训练中...,稍候
36次迭代后完成训练。
系数: [ 3.3045e-01 -1.5398e-07 5.6651e-02 7.3073e-08 -4.6018e-01 -7.5823e-06-1.1760e-08 4.6328e-01 -9.9697e-02 -1.0726e-01 1.0053e-02 -6.2893e-017.8053e-01]
截距:0.7805
对其余150个样本数据测试,准确率:90.6667%
经36次迭代,用X[train]、Y[train]训练的Lasso分类模型,对X[test]、Y[test]测试的正确率为90.667%{}。观察Lasso分类模型的系数,有一些元素的绝对值小于 1 0 − 4 10^{-4} 10−4。这意味着这些系数对应的特征数据对标签值的贡献微弱。删掉这些数据项对预测正确率的影响不大,且可提高训练线性模型的效率。下列代码作这样的尝试,追加在前两个程序尾部。
……
a = np.where(np.abs(coef) < 1e - 4)[0] #LASSO回归绝对值小于1/10000的系数下标
print('LASSO回归绝对值小于1/10000的系数下标:%s'%a)
X = np.delete(X, a, axis=1) #删掉这些系数对应的特征数据
print('LINE REGRESSION:')
heart_failure = LinearClassifier() #构造线性回归模型
heart_failure.fit(X[train], Y[train]) #训练模型
coef, inte=heart_failure.coef_inte()
print('系数:', coef)
print('截距:%.4f'%inte)
acc = heart_failure.score(X[test], Y[test]) * 100 #测试模型
print('对其余%d个样本数据测试,准确率:%.4f'%(m - m // 2, acc) + '%')
程序第1行的省略号表示程序8.6、8.7的代码。第2行调用numpy的where函数计算LassoClassifier对象表示的Lasso分类模型的系数coef中绝对值小于 1 0 − 4 10^{-4} 10−4的下标集a。第4行在X中删除由a指示的数据列。第6行将heart_{}failure声明为线性分类模型。第7行用X[train]、Y[train]训练线性分类模型。第11行对X[test]、Y[test]测试该模型。运行程序,输出
……
LASSO回归绝对值小于1/10000的系数下标:[1 3 5 6]
LINE REGRESSION:
训练中...,稍候
16次迭代后完成训练。
系数: [ 6.1677e-03 4.5319e-05 -9.4294e-03 7.5720e-02 -9.3499e-03 -1.5180e-014.0119e-02 -2.4872e-03]
截距:1.8346
对其余150个样本数据测试,准确率:90.6667%
即特征数据降维后,线性分类模型经16次迭代得到训练,测试知正确率与降维前保持一致。
写博不易,敬请支持:
如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!