此系列文章提炼《Python机器学习基础教程》最核心要点
第四章 数据表示与特征工程
一、分类变量
1、One-Hot编码(虚拟变量)
- 1)检查字符串编码的分类数据(可能有表示不同但是含义相同的数据:man、male等)
print(data.gender.value_counts())
- 2)利用get_dummies函数自动变换字符串和分类的列
data_dummies=pd.get_dummies(data)
- 3)用values属性将DataFrame转化为Numpy数组
features = data_dummies.loc[:, 'feature_1':'feature_k'] X = features.values y = data_dummies['target_1'].values #二分类时target也会变为两列,这个时候调出一列正好是0、1变量
- 4)注意:要在同时含有训练和测试数据的数据集调用get_dummies
2、数字编码的分类变量
用OneHotEncoder或替换时转换为字符串
demo_df['Integer Feature'] = demo_df['Integer Feature'].astype(str)
二、分箱、离散化、线性模型与树
1、具体操作
bins = np.linspace(-3, 3, 11)
#创建-3到3中10个均匀分布的箱子
which_bin = np.digitize(X, bins=bins)
#记录每个数据点所属的箱子
2、特点
一个箱子内所有点,任何模型会预测相同的值
分箱特征提高线性模型性能,决策树模型准确率降低
三、交互特征与多项式特征
1、使用分箱扩展连续特征
- 1)重新加入原始特征(向分箱数据上的线性模型添加斜率:图中x轴)
X_combined = np.hstack([X, X_binned]) reg = LinearRegression().fit(X_combined, y) line_combined = np.hstack([line, line_binned]) reg.predict(line_combined)
- 2)添加交互特征或乘积特征(每个箱子有不同的斜率)
X_product = np.hstack([X_binned,X* X_binned]) reg = LinearRegression().fit(X_product, y) line_product = np.hstack([line_binned, line*line_binned]) reg.predict(line_product)
2、使用原始特征的多项式
- 1)具体操作
from sklearn.preprocessing import PolynomialFeatures poly = PolynomialFeatures(degree=10, include_bias=False) #直到x**10的多项式,include_bias默认为False则添加恒等于一的常数特征 poly.fit(X) X_poly = poly.transform(X) poly.get_feature_names() #这一行用来查看获得特征的语义
- 2)多项式回归模型(多项式特征与线性回归一同使用)
reg = LinearRegression().fit(X_poly, y) line_poly = poly.transform(line) reg.predict(line_poly)
四、单变量非线性变换
log和exp函数可以帮助参数调节数据的相对比例,从而改进线性模型或神经网络的学习效果
X_train_log=np.log(X_train)
X_train_exp=np.exp(X_train)
使用:特征和目标之间存在非线性关系
五、自动化特征选择
1、概述
特征选择的原因:过多的特征会使得模型更为复杂
判断特征作用大小的基本策略:单变量统计、基于模型的选择、迭代选择(都是监督方法)
2、单变量统计
- 1)概念
操作:计算每个特征和目标值之间的关系是否存在统计显著性,然后选择具有最高置信度的特征(分类问题——方差分析)
使用阈值:SelectKBest(选择固定个数k个特征)、SelectPercentile(选择固定百分比的特征) - 2)具体操作
from sklearn.feature_selection import SelectPercentile select = SelectPercentile(percentile=50) #选择前50%的特征 select.fit(X_train, y_train) X_train_selected = select.transform(X_train)
- 3)可视化技巧
mask = select.get_support() #用get_support查看哪些变量被选中 print(mask) plt.matshow(mask.reshape(1, -1), cmap='gray_r') #将遮罩可视化,黑色为True,白色为False plt.xlabel("Sample index") plt.yticks(())
3、基于模型的特征选择
- 1)概念
使用一个监督学习模型判断每个特征的重要性
用特征选择的监督模型不一定和最终监督模型相同
与单变量选择不同,基于模型的选择同时考虑所有特征(可以获取交互项) - 2)具体操作
- A.使用包含100棵树的随机森林分类器来计算特征重要性
from sklearn.feature_selection import SelectFromModel from sklearn.ensemble import RandomForestClassifier select = SelectFromModel(RandomForestClassifier(n_estimators=100, random_state=42),threshold="median")
- B.实际拟合模型
select.fit(X_train, y_train) X_train_l1 = select.transform(X_train)
- C.查看性能
X_test_l1 = select.transform(X_test) score = LogisticRegression().fit(X_train_l1, y_train).score(X_test_l1, y_test) print("Test score: {:.3f}".format(score))
- A.使用包含100棵树的随机森林分类器来计算特征重要性
4、迭代特征选择
- 1)概念
构建一系列模型,每个模型使用不同数量的特征
方法:逐一添加或逐一删除(递归特征消除,RFE) - 2)具体操作
- A.构建模型
from sklearn.feature_selection import RFE select = RFE(RandomForestClassifier(n_estimators=100, random_state=42),n_features_to_select=40) select.fit(X_train, y_train)
- B.查看性能
X_train_rfe = select.transform(X_train) X_test_rfe = select.transform(X_test) score = LogisticRegression().fit(X_train_rfe, y_train).score(X_test_rfe, y_test) print("Test score: {:.3f}".format(score))
- A.构建模型
六、利用专家知识
第五章 模型评估与改进
一、交叉验证
1、概述
交叉验证:评估泛化性能的统计学方法。数据集被多次划分,需要训练多个模型
优点:多次划分:可以看出模型对训练集选择的敏感度
缺点:增加了计算成本
目的:评估给定算法在特定数据集上训练后的泛化性能(不是一种构建可用于新数据模型的方法)
2、基本操作(k折交叉验证)
from sklearn.model_selection import cross_val_score
logreg = LogisticRegression()
scores = cross_val_score(logreg, iris.data, iris.target, cv=5)
#cv:指定交叉验证折数
print("Cross-validation scores: {}".format(scores))
3、分层k折交叉验证(每个折中类别的比例与整个数据集比例相同)
- 1)kfold交叉验证分离器(可作为cv参数)
from sklearn.model_selection import KFold kfold = KFold(n_splits=3, shuffle=True, random_state=0) #shuffle:将数据打乱(可以代替分层,random_state固定以获得可重复的打乱效果) print("Cross-validation scores:\n{}".format(cross_val_score(logreg, iris.data, iris.target, cv=kfold)))
- 2)留一法交叉验证(每折只包含单个样本的k折交叉验证)
from sklearn.model_selection import LeaveOneOut loo = LeaveOneOut() scores = cross_val_score(logreg, iris.data, iris.target, cv=loo) #留一交叉验证中,每次划分单个数据点作为测试集,非常耗时,小数据使用较好 print("Number of cv iterations: ", len(scores)) print("Mean accuracy: {:.2f}".format(scores.mean()))
- 3)打乱交叉验证
from sklearn.model_selection import ShuffleSplit shuffle_split = ShuffleSplit(test_size=.5, train_size=.5, n_splits=10) #每次划分为训练集取样train_size个点,测试集取样test_size个点,重复n_iter次,每次迭代使用部分数据:train_size+test_size<1 scores = cross_val_score(logreg, iris.data, iris.target, cv=shuffle_split) print("Cross-validation scores:\n{}".format(scores))
- 4)分组交叉验证(适用于数据分组高度相关,如人脸表情识别,想要泛化到新的人)
from sklearn.model_selection import GroupKFold groups = [0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3] scores = cross_val_score(logreg, X, y, groups, cv=GroupKFold(n_splits=3)) #每次划分中,每个组会整体出现在训练集或测试集中 print("Cross-validation scores:\n{}".format(scores))
二、网格搜索
1、概述
目的:找到一个模型提供最佳泛化性能的参数
简单的编程实现
for gamma in [0.001, 0.01, 0.1, 1, 10, 100]:
for C in [0.001, 0.01, 0.1, 1, 10, 100]:
svm = SVC(gamma=gamma, C=C)
svm.fit(X_train, y_train)
score = svm.score(X_test, y_test)
2、降低参数过拟合风险——验证集
- 1)两次划分
X_trainval, X_test, y_trainval, y_test = train_test_split(iris.data, iris.target, random_state=0) X_train, X_valid, y_train, y_valid = train_test_split(X_trainval, y_trainval, random_state=1)
- 2)改进核心代码:在验证集上评估模型
score = svm.score(X_valid, y_valid)
- 3)循环结束后:在训练+验证集上重构模型,在测试集上评估
svm.fit(X_trainval, y_trainval) test_score = svm.score(X_test, y_test)
3、带交叉验证的网格搜索
- 1)改进核心代码:执行交叉验证并计算平均精度
scores = cross_val_score(svm, X_trainval, y_trainval, cv=5) score = np.mean(scores)
- 2)利用sklearn中的估计器
param_grid = {'C': [0.001, 0.01, 0.1, 1, 10, 100],'gamma': [0.001, 0.01, 0.1, 1, 10, 100]} #需要一个字典指定搜索参数 from sklearn.model_selection import GridSearchCV grid_search = GridSearchCV(SVC(), param_grid, cv=5,return_train_score=True) grid_search.fit(X_train, y_train) #仍需要划分训练测试集 print("Test set score: {:.2f}".format(grid_search.score(X_test, y_test))) #未使用测试集选择参数:best_score_是在训练集上交叉验证得到的,与之前全数据集得到的score不同
- 3)分析结果
results = pd.DataFrame(grid_search.cv_results_) #可考虑用热图可视化
- 4)非网格搜索:param_grid可改为字典组成的列表
param_grid = [{'kernel': ['rbf'],'C': [0.001, 0.01, 0.1, 1, 10, 100],'gamma': [0.001, 0.01, 0.1, 1, 10, 100]},{'kernel': ['linear'],'C': [0.001, 0.01, 0.1, 1, 10, 100]}]
三、评估指标与评分
1、回归指标:使用默认的R^2(由所有回归器的score方法给出)
2、不平和数据集:一个类占据绝大多数
3、二分类指标
- 1)混淆矩阵
from sklearn.metrics import confusion_matrix confusion = confusion_matrix(y_test, pred_logreg) #这里confusion是一个2*2的数组
- 2)评估指标
- A.准确率:正例中真正正例比例
- B.召回率:真正正例被预测为正例比例
- C.F1分数:准确率与召回率的调和平均
- D.绘制报表
from sklearn.metrics import classification_report print(classification_report(y_test, svc.predict(X_test)))
- E.绘制准确率-召回率曲线
from sklearn.metrics import precision_recall_curve precision, recall, thresholds = precision_recall_curve(y_test, svc.decision_function(X_test)) plt.plot(precision, recall, label="precision recall curve")
- F.总计曲线:平均准确率(曲线积分面积,返回浮点数)
from sklearn.metrics import average_precision_score ap_svc = average_precision_score(y_test, svc.decision_function(X_test))
- G.ROC曲线(受试者工作特征曲线,假正例率和真正例率)
from sklearn.metrics import roc_curve fpr, tpr, thresholds = roc_curve(y_test, svc.decision_function(X_test)) plt.plot(fpr, tpr, label="ROC Curve")
- H.总结曲线:曲线下面积(AUC,返回浮点数)
from sklearn.metrics import roc_auc_score svc_auc = roc_auc_score(y_test, svc.decision_function(X_test))
4、多分类指标
- 1)多分类指标的混淆矩阵
- 2)不平衡数据集:f-分数(多分类版本)
- 对每个类别计算一个二分类f-分数(其他所有类别都是反类)
- 使用如下策略对按类别的f-分数进行平均
- 宏平均:所有类别给出相同权重,无论样本大小
- 加权平均:每个类别的支持作为权重来计算按类别f-分数平均值
- 微平均:计算所有类别中FP、FN、TP总数,从而计算准确率、召回率和f-分数
- 使用方式
- 对每个样本同等看待:微平均f-分数
f1_score(y_test, pred, average="micro")
- 对每个类别同等看待:宏平均f-分数
f1_score(y_test, pred, average="macro")
- 对每个样本同等看待:微平均f-分数
5、在模型选择中使用评估指标
- 目的:在使用GridSearchCV或cross_val_score进行模型选择时使用AUC等指标
- 方法:scoring参数
- 交叉验证
roc_auc = cross_val_score(SVC(), X, y == 1,scoring="roc_auc") #分类问题默认就是‘accuracy’(准确率),可以改为‘roc_auc’(AUC)
- 网格搜索
grid = GridSearchCV(SVC(), param_grid=param_grid, scoring="roc_auc") #与上同理
- 交叉验证
- 常用的是scoring参数
- 分类问题
- 准确率(accuracy)
- ROC曲线下面积(roc_auc)
- 准确率-召回率曲线下面积(average_precision)
- 四个二分类f1分数及加权变体(f1, f1_macro, f1_micro, f1_weighted)
- 回归问题
- R^2分数(r2)
- 均方误差(mean_squared_error)
- 平均绝对误差(mean_absolute_error)
- 分类问题
四、小结
数据划分:训练集-训练模型;验证集-选择模型与参数;测试集-模型评估
明确机器学习的最终目的:确保用于模型评估与选择的指标能够很好地替代模型的实际用途
第六章 算法链与管道
一、用预处理进行参数选择
- 引入:在进行任何预处理之前完成数据集的划分(交叉验证位于处理过程的最外层循环)
- Pipeline类
将多个处理步骤合并(glue)为单个估计器
本身具有fit、predict和score方法
最常见:将预处理步骤(如缩放)与一个监督模型(如分类器)连接在一起
二、构建管道
from sklearn.pipeline import Pipeline
pipe=Pipeline([("scaler", MinMaxScaler()), ("svm",SVC())])
#创建了两个步骤,第一个叫scaler,是MinMaxScaler的实例,第二个叫svm,是SVC()的实例
pipe.fit(X_train, y_train)
#拟合管道
print("Test score: {:.2f}".format(pipe.score(X_test, y_test)))
#直接用管道的score方法进行评估
三、在网格搜索中使用管道
param_grid = {'svm__C': [0.001, 0.01, 0.1, 1, 10, 100],'svm__gamma': [0.001, 0.01, 0.1, 1, 10, 100]}
#为网格定义参数网络:步骤名称+双下划线+参数名称
grid = GridSearchCV(pipe, param_grid=param_grid, cv=5)
grid.fit(X_train, y_train)
#现在可以仅适用训练部分进行MinMaxScaler拟合,验证和测试集都没有变化,因此测试部分的信息不会泄露到参数搜索中
print("Best cross-validation accuracy: {:.2f}".format(grid.best_score_))
print("Test set score: {:.2f}".format(grid.score(X_test, y_test)))
print("Best parameters: {}".format(grid.best_params_))
四、通用的管道接口
1、用make_pipeline方便地创建管道
pipe_short = make_pipeline(MinMaxScaler(), SVC(C=100))
区别:会自动制定步骤名称,名称在step属性中
2、利用named_steps访问步骤属性
components = pipe.named_steps["pca"].components_
3、访问网格搜索管道中的属性
print("Best estimator:\n{}".format(grid.best_estimator_))
#访问GridSearchCV找到的最佳LogisticRegression模型的系数
print("Logistic regression coefficients:\n{}".format(grid.best_estimator_.named_steps["logisticregression"].coef_))
#访问每个输入特征相关权重
五、网格搜索预处理步骤与模型参数
1、目的:使用监督任务的输出调节预处理参数
from sklearn.preprocessing import PolynomialFeatures
pipe = make_pipeline(StandardScaler(),PolynomialFeatures(),Ridge())
#缩放数据、计算多项式特征和岭回归放在同一个pipe里
param_grid = {'polynomialfeatures__degree': [1, 2, 3],'ridge__alpha': [0.001, 0.01, 0.1, 1, 10, 100]}
#用网格选择多项式/交互
grid = GridSearchCV(pipe, param_grid=param_grid, cv=5, n_jobs=-1)
grid.fit(X_train, y_train)
2、Tips:用热图将交叉验证结果可视化
plt.matshow(grid.cv_results_['mean_test_score'].reshape(3,-1),vmin=0,cmap='viridis')
plt.xlabel('ridge__alpha')
plt.ylabel('polynomialfeatures__degree')
plt.xticks(range(len(param_grid['ridge__alpha'])),param_grid['ridge__alpha'])
plt.yticks(range(len(param_grid['polynomialfeatures__degree'])),param_grid['polynomialfeatures__degree'])
plt.colorbar()
3、查看最佳模型和对应分数
print("Best parameters: {}".format(grid.best_params_))
print("Test-set score: {:.2f}".format(grid.score(X_test, y_test)))
六、网格搜索选择使用哪个模型
使用搜索网格列表,跳过步骤(如random forest不需要预处理)则设置为None
param_grid = [{'classifier': [SVC()], 'preprocessing': [StandardScaler(), None],'classifier__gamma': [0.001, 0.01, 0.1, 1, 10, 100],'classifier__C': [0.001, 0.01, 0.1, 1, 10, 100]},{'classifier': [RandomForestClassifier(n_estimators=100)],'preprocessing': [None], 'classifier__max_features': [1, 2, 3]}]
网格如此定义,其余同理