3.Machine Learning with Python
读者将会发现,机器学习的核心模型已经被scikit-learn等工具包非常好的模块化了,调用起来非常简单,仅需要几行代码,但是一个完整的、有效的机器学习工程项目却包括很多步骤,可以包括数据导入,数据可视化理解,前处理,特征选择,模型训练,参数调整,模型预测,模型评估,后处理等多个步骤,一个在真实世界中有效的模型可能需要工作者对数据的深入理解,以选择各个步骤合适的方法。
本章中我们进行实例讲解,根据BreastCance癌症数据集进行特征筛选和预测。通过本章教程,读者可以对机器学习的基本概念方法和具体流程有所了解,而且可以通过实践更好地掌握python相关工具包的使用,为后续的应用做好准备。

1) Data

BreastCance癌症数据集可以在该链接Files needed by this Tutorial中的清华云Bioinformatics Tutorial / Files路径下的相应文件夹中下载。
    数据说明
1) 文件有11个列,第1个列为id号,第2-10列为特征,11列为标签(benign为良性、malignant为恶性)。 2) 数据集有458个良性(benign)样本和241个恶性(malignant)样本 3) 数据集有Cl.thickness,Cell.size,Cell.shape,Marg.adhesion,Epith.c.size,Bare.nuclei,Bl.cromatin,Normal.nucleoli,Mitoses等9个特征,每个特征取值为1-10。
部分数据如下:
Id
Cl.thickness
Cell.size
Cell.shape
Marg.adhesion
Epith.c.size
Bare.nuclei
Bl.cromatin
Normal.nucleoli
Mitoses
Class
1000025
5
1
1
1
2
1
3
1
1
benign
1002945
5
4
4
5
7
10
3
2
1
benign
1015425
3
1
1
1
2
2
3
1
1
benign
1016277
6
8
8
1
3
4
3
7
1
benign
1017023
4
1
1
3
2
1
3
1
1
benign
1017122
8
10
10
8
7
10
9
7
1
malignant
Cl.thickness: Clump Thickness Cell.size: Uniformity of Cell Size Cell.shape: Uniformity of Cell Shape Marg.adhesion: Marginal Adhesion Epith.c.size: Single Epithelial Cell Size Bare.nuclei: Bare Nuclei Bl.cromatin: Bland Chromatin Normal.nucleoli: Normal Nucleoli Mitoses: Mitoses 如需了解更多关于BreastCancer数据集信息,可参考mlbench的文档。
    学习任务
      1)从9个特征中找到预测效果最好的3个特征组合。
      2)利用最佳的3个特征构建预测模型,并评估模型效果。

2) Load python packages

这里我们会导入一些后续操作需要的python工具包,它们的相关文档如下,请有兴趣的读者重点学习和了解scikit-learn工具包。
tips: Anaconda并没有集成seaborn的最新版本,请使用pip更新seaborn:pip install seaborn==0.9.0
1
import pandas as pd
2
import numpy as np
3
import matplotlib.pyplot as plt
4
import seaborn as sns
5
from sklearn.preprocessing import StandardScaler
6
from sklearn.model_selection import train_test_split
7
from sklearn.model_selection import StratifiedKFold
8
from sklearn.model_selection import GridSearchCV
9
from sklearn.tree import DecisionTreeClassifier
10
from sklearn.svm import LinearSVC, SVC
11
from sklearn.ensemble import RandomForestClassifier
12
from sklearn.linear_model import LogisticRegression
13
from sklearn.metrics import
14
roc_curve,roc_auc_score,auc,precision_recall_curve,average_precision_score,accuracy_score
Copied!

3) Load and pre-process the data

我们需要导入BreastCance癌症数据,然后进行空缺值填充、归一化处理。
    数据导入:
1
data = pd.read_csv('BreastCancer.csv',sep=',')
2
feature = ['Cl.thickness', 'Cell.size', 'Cell.shape', 'Marg.adhesion', 'Epith.c.size', 'Bare.nuclei', 'Bl.cromatin', 'Normal.nucleoli', 'Mitoses']
3
X=data[feature]
4
Y=np.array(data['Class'].replace('benign',0).replace('malignant',1))
Copied!
    利用均值进行空缺值填充:
1
X_mean = X.mean(axis=0)
2
for i in range(len(X.T)):
3
X.iloc[:, i] = X.iloc[:, i].fillna(X_mean[i])
Copied!
    使用standard/z-score scaling 对数据做scaling:
1
X_sd = StandardScaler().fit_transform(X)
2
X = pd.DataFrame(X_sd)
3
X.columns=feature
Copied!

4) Dividing data

之前我们已经对数据进行了一些分析,并且做了一些基本的预处理,接下来我们需要对数据进行划分,得到Discovery set(Training/Test set)和Validation Set。
    Discovery Set 包括
      Training Set:用于训练模型;
      Test Set:用于确定模型参数,这里我们用交叉验证的方法进行划分Training seet和Test set用于特征选择;
    Validation Set:不参与模型训练过程,仅用于评价模型效果。
Datasets in Machine Learning
因为模型总是会在某种程度上过拟合训练数据,因此在训练数据上评估模型是有偏的,模型在训练集上的表现总会比测试集上好一些。因为模型总是可以学到数据中隐藏的模式和分布,如果样本间彼此的差异比较大,过拟合问题就会得到一定程度的减轻。而如果数据的量比较大,模型在训练集和测试集上的表现差异就会减小。

4a) Whole Data Set → Discovery Set/Validation Set

这里我们首先使用train_test_split 方法来随机的将20%的数据预留为一个独立的Validation Set,80%数据为Discovery set。
1
random_state = np.random.RandomState(1289237)
2
X_discovery, X_validation, y_discovery, y_validation = train_test_split(X, Y, test_size=0.2, random_state=random_state)
3
X_discovery.index = range(len(X_discovery))
4
X_validation.index = range(len(X_validation))
5
print('number of discovery samples: {}, validation samples: {}'.format(X_discovery.shape[0], X_validation.shape[0]))
Copied!
1
number of discovery samples: 559, test samples: 140
Copied!

4b) Discovery set → Training Set/Test Set

同时,我们将剩下的80%的Discovery set随机划分为Training Set and Test Set,我们可以通过training 和 test sets进行多折交叉验证(cross validation),例如,可以利用5-fold cross validation计算得到5个子Test Sets的平均AUC,然后评估不同特征组合并选取一个最优的。

5) Feature selection based on cross-validation

我们可以在Discovery set上做 k-fold Cross-validation,通过在k个子Test Sets上的平均AUC帮助我们评估和选择一些超参数,例如该选用哪种模型(LR,RF,DT,SVM等),该选用多少个features等。
下面我们展示一个利用Cross-validation进行封装式特征选择的例子:
    模型函数(clf_select)
我们首先自定义了一个函数clf_select,可以利用这个函数选用LR,RF,DT,SVM等模型中的一个(注意选用哪个模型是一个超参数)
1
def clf_select(name):
2
if name =='DT':
3
clf = DecisionTreeClassifier(max_depth=5, min_samples_leaf=5, criterion='gini')
4
elif name =='DT_cv':
5
tree_para = {'max_depth': [3,5,7,9]}
6
clf = GridSearchCV(DecisionTreeClassifier(), tree_para, cv=5)
7
elif name == 'SVM':
8
clf = SVC(kernel='rbf', probability=True, C=1)
9
elif name == 'SVM_cv':
10
tree_para = { 'C':[0.00001, 0.0001, 0.001, 0.01, 0.1, 1, 10, 100, 1000, 10000, 100000]}
11
clf = GridSearchCV(SVC(kernel= 'rbf',probability=True), tree_para, cv=5)
12
elif name == 'RF':
13
clf = RandomForestClassifier(n_estimators=50, max_depth=5)
14
elif name == 'RF_cv':
15
tree_para = {'n_estimators': [25, 50, 75],'max_depth': [3, 4, 5]}
16
clf = GridSearchCV(RandomForestClassifier(), tree_para, cv=5)
17
elif name == 'LR_cv':
18
tree_para = {'C': [0.00001, 0.0001, 0.001, 0.01, 0.1, 1, 10, 100, 1000, 10000, 100000]}
19
clf = GridSearchCV(LogisticRegression(penalty='l2',solver='liblinear'), tree_para, cv=5)
20
return clf
Copied!
    计算可能的特征组合
我们枚举出所有的3个特征的组合,注意特征组合包含的特征个数也是一个超参数,这里我们以3个特征的组合为例。
1
from itertools import combinations
2
feature_list=[]
3
for i in combinations(feature, 3):
4
feature_list.append(list(i))
Copied!
    对每个特征组合进行交叉验证计算5个子Test Sets的平均AUC
1
# 交叉验证的平均AUC
2
result_train = pd.DataFrame(columns={'feature', 'AUC_mean'})
3
result_test = pd.DataFrame(columns={'feature', 'AUC_mean'})
4
5
for j in range(len(feature_list)):
6
print(j)
7
# 交叉验证划分
8
skf = StratifiedKFold(n_splits=5,random_state=1,shuffle=True)
9
# 交叉验证中每一折结果
10
result_train_= pd.DataFrame(columns={'num', 'AUC'})
11
result_test_ = pd.DataFrame(columns={'num', 'AUC'})
12
n=0
13
for train, test in skf.split(list(X_discovery.index), y_discovery):
14
# Training and Test Set
15
X_train = X_discovery.loc[train,feature_list[j]]
16
X_test = X_discovery.loc[test,feature_list[j]]
17
y_train = y_discovery[train]
18
y_test = y_discovery[test]
19
20
# 模型训练,我们自定义clf_select函数
21
clf = clf_select('DT_cv')
22
clf.fit(X_train, y_train)
23
24
# 模型预测结果
25
pred_proba_train = clf.predict_proba(X_train)
26
fpr_train, tpr_train, thresholds = roc_curve(y_train, pred_proba_train[:, 1])
27
roc_auc_train = auc(fpr_train, tpr_train)
28
pred_proba_test = clf.predict_proba(X_test)
29
fpr_test, tpr_test, thresholds = roc_curve(y_test, pred_proba_test[:, 1])
30
roc_auc_test = auc(fpr_test, tpr_test)
31
32
result_train_.loc[n,'num']=n
33
result_train_.loc[n,'AUC'] = roc_auc_train
34
result_test_.loc[n,'num']=n
35
result_test_.loc[n,'AUC'] = roc_auc_test
36
n=n+1
37
38
# 模型Test Set平均AUC计算
39
result_train.loc[j,'feature']=','.join(feature_list[j])
40
result_train.loc[j, 'AUC_mean'] = result_train_['AUC'].mean()
41
result_test.loc[j,'feature']=','.join(feature_list[j])
42
result_test.loc[j, 'AUC_mean'] = result_test_['AUC'].mean()
Copied!
    根据5个子Test Sets的平均AUC选择最佳特征组合
1
best_feature=result_test.loc[result_test.sort_values('AUC_mean',ascending=False).index[0],'feature'].split(',')
Copied!
结果为:
1
'Cl.thickness', 'Cell.size', 'Bare.nuclei'
Copied!

6) Evaluate on validation set

    我们首先利用cross-validation选择好的超参数重新对整个Discovery set进行训练得到一个预测模型
1
clf = clf_select('DT_cv')
2
clf.fit(X_discovery.loc[:, best_feature], y_discovery)
Copied!
    接着,我们利用该预测模型在Validation set上进行评估,绘制ROC
1
y_predict=clf.predict(X_validation.loc[:, best_feature])
2
proba=clf.predict_proba(X_validation.loc[:, best_feature]).T[1]
3
fpr, tpr, thresholds = roc_curve(y_validation, proba)
4
roc_auc = auc(fpr, tpr)
5
6
# 画ROC曲线
7
plt.figure(figsize=(4,4))
8
plt.plot(fpr, tpr, '-', color='b', label='Validation AUC of {:.4f}'.format(roc_auc), lw=2)
9
plt.plot([0, 1], [0, 1], '--', color=(0.6, 0.6, 0.6), label='Random Chance')
10
plt.xlim([0, 1])
11
plt.ylim([0, 1])
12
plt.title('ROC curve of test data')
13
plt.xlabel('FPR')
14
plt.ylabel('TPR')
15
plt.legend(loc='best',fontsize='small')
16
plt.tight_layout()
17
plt.show()
18
plt.close()
Copied!
png
可以看到AUROC接近于1,可以认为模型的分类效果很好。
一些超参数(例如哪个模型,哪些features)我们是通过Discovery Set上的cross-validation时计算的多个子Test Sets的AUC平均值选取好了一个最优的,最后的时候我们仍然可以再次在Validation Set上观察和评估一下这些不同的超参数(例如比较一下多个不同的模型)的泛化能力。

7) Homework

    按照教程中的流程,对我们给定的qPCR数据进行特征筛选和预测模型构建,给出最佳的模型组合和Validation Sets上的ROC曲线。数据集qPCR_data可从
    该链接Files needed by this Tutorial中的清华云Bioinformatics Tutorial / Files路径下的相应文件夹中下载数据文件,包括11个特征,两种类别(正常NC和病人HCC)。
    数据特征:第1列为sample id,第2-12列为特征(包含11个基因),第13列为样本标签
    数据标签处理:正样本为NC,负样本为HCC
    数据预处理:1)去除含有空缺值的样本 2)对数据进行归一化
    数据集划分:预留一个独立的Validation Set(参考教程中的20%),程序运行最开头加上random_state = np.random.RandomState(1289237)保证划分一致
    分类器模型:LR, SVM, DT, RF
    编程工具:R/python
    作业要求:上传word/pdf文档附件,记录处理过程所用代码,并绘制ROC曲线。
Last modified 2mo ago