上篇博客说的是逻辑回归的基本内容,包括公式推导,总体来说,和普通线性回归差不多。这篇博客使用逻辑回归基于病理数据进行乳腺癌预测。
数据
数据的来源: Breast Cancer Wisconsin (Original) Data Set
数据概要:
数据的属性
翻译过来,大致内容:
属性信息:
- 样本编号:id编号
- 簇厚:1 - 10
- 细胞大小均匀性:1 - 10
- 细胞形状均匀性:1 - 10
- 边缘附着力:1 - 10
- 单个上皮细胞大小:1 - 10
- 裸核:1 - 10
- 温和的染色质:1 - 10
- 正常核仁:1 - 10
- 有丝分裂:1 - 10
- 类别:(良性2人,恶性4人)
看几条具体数据
代码
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import pandas as pd
import warnings
import sklearn
from sklearn.linear_model import LogisticRegressionCV,LinearRegression # 交叉验证逻辑回归
from sklearn.linear_model.coordinate_descent import ConvergenceWarning # 普通逻辑回归
from sklearn.model_selection import train_test_split # 数据划分
from sklearn.preprocessing import StandardScaler # 标准化
## 设置字符集,防止中文乱码
mpl.rcParams['font.sans-serif']=[u'simHei']
mpl.rcParams['axes.unicode_minus']=False
## 拦截异常
warnings.filterwarnings(action = 'ignore', category=ConvergenceWarning)
## 数据读取并处理异常数据
path = "datas/breast-cancer-wisconsin.data"
names = ['id','Clump Thickness','Uniformity of Cell Size','Uniformity of Cell Shape',
'Marginal Adhesion','Single Epithelial Cell Size','Bare Nuclei',
'Bland Chromatin','Normal Nucleoli','Mitoses','Class']
df = pd.read_csv(path, header=None,names=names)
datas = df.replace('?', np.nan).dropna(how = 'any') # 只要有列为空,就进行删除操作
datas.head(5) ## 显示一下
# 1. 数据提取以及数据分隔
## 提取
X = datas[names[1:10]]
Y = datas[names[10]]
## 分隔
X_train,X_test,Y_train,Y_test = train_test_split(X,Y,test_size=0.1,random_state=0)
# 2. 数据格式化(归一化)
ss = StandardScaler()
X_train = ss.fit_transform(X_train) ## 训练模型及归一化数据
# 3. 模型构建及训练
## penalty: 过拟合解决参数,l1或者l2
## solver: 参数优化方式
### 当penalty为l1的时候,参数只能是:liblinear(坐标轴下降法);
### nlbfgs和cg都是关于目标函数的二阶泰勒展开
### 当penalty为l2的时候,参数可以是:lbfgs(拟牛顿法)、newton-cg(牛顿法变种),seg(minibatch)
# 维度<10000时,lbfgs法比较好, 维度>10000时, cg法比较好,显卡计算的时候,lbfgs和cg都比seg快
## multi_class: 分类方式参数;参数可选: ovr(默认)、multinomial;这两种方式在二元分类问题中,效果是一样的;在多元分类问题中,效果不一样
### ovr: one-vs-rest, 对于多元分类的问题,先将其看做二元分类,分类完成后,再迭代对其中一类继续进行二元分类
### multinomial: many-vs-many(MVM),即Softmax分类效果
## class_weight: 特征权重参数
### TODO: Logistic回归是一种分类算法,不能应用于回归中(也即是说对于传入模型的y值来讲,不能是float类型,必须是int类型)
lr = LogisticRegressionCV(multi_class='ovr',fit_intercept=True, Cs=np.logspace(-2, 2, 20), cv=2, penalty='l2', solver='lbfgs', tol=0.01)
re=lr.fit(X_train, Y_train)
# 4. 模型效果获取
r = re.score(X_train, Y_train)
print ("R值(准确率):", r)
print ("稀疏化特征比率:%.2f%%" % (np.mean(lr.coef_.ravel() == 0) * 100))
print ("参数:",re.coef_)
print ("截距:",re.intercept_)
print(re.predict_proba(X_test)) # 获取sigmoid函数返回的概率值
R值(准确率): 0.9706840390879479
稀疏化特征比率:0.00%
参数: [[1.3926311 0.17397478 0.65749877 0.8929026 0.36507062 1.36092964
0.91444624 0.63198866 0.75459326]]
截距: [-1.02717163]
[[6.61838068e-06 9.99993382e-01]
[3.78575185e-05 9.99962142e-01]
[2.44249065e-15 1.00000000e+00]
[0.00000000e+00 1.00000000e+00]
[1.52850624e-03 9.98471494e-01]
[6.67061684e-05 9.99933294e-01]
[6.75536843e-07 9.99999324e-01]
[0.00000000e+00 1.00000000e+00]
[2.43117004e-05 9.99975688e-01]
[6.13092842e-04 9.99386907e-01]
[0.00000000e+00 1.00000000e+00]
[2.00330728e-06 9.99997997e-01]
[0.00000000e+00 1.00000000e+00]
[3.78575185e-05 9.99962142e-01]
[4.65824155e-08 9.99999953e-01]
[5.47788703e-10 9.99999999e-01]
[0.00000000e+00 1.00000000e+00]
[0.00000000e+00 1.00000000e+00]
[0.00000000e+00 1.00000000e+00]
[6.27260778e-07 9.99999373e-01]
[3.78575185e-05 9.99962142e-01]
[3.85098865e-06 9.99996149e-01]
[1.80189197e-12 1.00000000e+00]
[9.44640398e-05 9.99905536e-01]
[0.00000000e+00 1.00000000e+00]
[0.00000000e+00 1.00000000e+00]
[4.11688915e-06 9.99995883e-01]
[1.85886872e-05 9.99981411e-01]
[5.83016713e-06 9.99994170e-01]
[0.00000000e+00 1.00000000e+00]
[1.52850624e-03 9.98471494e-01]
[0.00000000e+00 1.00000000e+00]
[0.00000000e+00 1.00000000e+00]
[1.51713085e-05 9.99984829e-01]
[2.34685008e-05 9.99976531e-01]
[1.51713085e-05 9.99984829e-01]
[0.00000000e+00 1.00000000e+00]
[0.00000000e+00 1.00000000e+00]
[2.34685008e-05 9.99976531e-01]
[0.00000000e+00 1.00000000e+00]
[9.97563915e-07 9.99999002e-01]
[1.70686321e-07 9.99999829e-01]
[1.38382134e-04 9.99861618e-01]
[1.36080718e-04 9.99863919e-01]
[1.52850624e-03 9.98471494e-01]
[1.68154251e-05 9.99983185e-01]
[6.66097483e-04 9.99333903e-01]
[0.00000000e+00 1.00000000e+00]
[9.77502258e-07 9.99999022e-01]
[5.83016713e-06 9.99994170e-01]
[0.00000000e+00 1.00000000e+00]
[4.09496721e-06 9.99995905e-01]
[0.00000000e+00 1.00000000e+00]
[1.37819117e-06 9.99998622e-01]
[6.27260778e-07 9.99999373e-01]
[4.52734741e-07 9.99999547e-01]
[0.00000000e+00 1.00000000e+00]
[8.88178420e-16 1.00000000e+00]
[1.06976766e-08 9.99999989e-01]
[0.00000000e+00 1.00000000e+00]
[2.45780192e-04 9.99754220e-01]
[3.92389040e-04 9.99607611e-01]
[6.10681985e-05 9.99938932e-01]
[9.44640398e-05 9.99905536e-01]
[1.51713085e-05 9.99984829e-01]
[2.45780192e-04 9.99754220e-01]
[2.45780192e-04 9.99754220e-01]
[1.51713085e-05 9.99984829e-01]
[0.00000000e+00 1.00000000e+00]]
这里还需要详细的说明一下:
逻辑回归用于二分类,如果是二分类,和普通的逻辑回归是一样的,对于多分类有两种(通过multi_class参数设置)
ovr(默认):比如现在有ABCD四类,分别训练四个模型
- 模型1:A(对应为1类),BCD(对应为0类)
- 模型2:B(对应为1类),ACD(对应为0类)
- 模型3:C(对应为1类),ABD(对应为0类)
- 模型4:D(对应为1类),ACD(对应为0类)
对于样本x,如果通过模型1返回1,则该样本属于A类。所以最终转化成了四个二分类的问题。
multinomial:many-vs-many(MVM),即SoftMax分类效果。(后面博客会有详细介绍)
还有一点:对于逻辑回归,API中没有阈值参数,默认是以0.5为分割点,大于的为1类,小于的为0类。我们可以自行调整。
# # 5. 模型相关信息保存
# ## 引入包
# from sklearn.externals import joblib
# ## 要求文件夹必须存在
# joblib.dump(ss, "datas/logistic/ss.model") ## 将标准化模型保存
# # joblib.dump(lr, "datas/models/logistic/lr.model") ## 将模型保存
# # 模型加载
# ## 引入包
# from sklearn.externals import joblib
# oss = joblib.load("models/logistic/ss.model")
# olr = joblib.load("models/logistic/lr.model")
# 数据预测
## a. 预测数据格式化(归一化)
X_test = ss.transform(X_test) # 使用模型进行归一化操作
## b. 结果数据预测
Y_predict = re.predict(X_test)
## c. 图表展示
x_len = range(len(X_test))
plt.figure(figsize=(14,7), facecolor='w')
plt.ylim(0,6)
plt.plot(x_len, Y_test, 'ro',markersize = 8, zorder=3, label=u'真实值')
plt.plot(x_len, Y_predict, 'go', markersize = 14, zorder=2, label=u'预测值,$R^2$=%.3f' % re.score(X_test, Y_test))
plt.legend(loc = 'upper left')
plt.xlabel(u'数据编号', fontsize=18)
plt.ylabel(u'乳腺癌类型', fontsize=18)
plt.title(u'Logistic回归算法对数据进行分类', fontsize=20)
plt.show()
看一下效果:
红色的点
表示的真实值,绿色的点
是我们预测的值,最终结果还是比较不错的。