原文:地址
Author: Miao Fan (范淼), Ph.D. candidate on Computer Science.
Affiliation: Tsinghua University / New York University
[C.V.] [Google Scholar] [Special Talk in NYU]
Email: fanmiao.cslt.thu@gmail.com
声明:
下面这些内容,都是学习《Learning scikit-learn: Machine Learning in Python》这本书的心得和一些拓展,写到哪算哪。Scikit-learn这个包我关注了2年,发展迅速;特别是它提供商业使用许可,比较有前景。
对于机器学习实践的“选手”,这是本入门的好书,国内目前没有中文译文版,我就先吃吃螃蟹。我个人认为,如果能够比较熟练掌握 Scikit-learn中的各种现有成熟模型的使用以及超参数优化(其实对超参数优化在工程中更加重要),那么Kaggle多数的竞赛大家基本可以进入Top25%。
这份长篇笔记中的代码链接目前都在本地,不久我会上传到GITHUB上。
平心而论,只有使用这些模型的经验丰富了,才能在实战中发挥作用,特别是对超参数和模型本身局限性的理解,恐怕不是书本所能教会的。
另外,更是有一些可以尝试的,并且曾经在Kaggle竞赛中多次获奖的模型包,比如 Xgboost, gensim等。Tensorflow究竟是否能够取得Kaggle竞赛的奖金,我还需要时间尝试。
同时,我个人近期也参与了《Deep Learning》这本优质新书多个章节贡献和校对,与三位作者平时的交流也深受启发。如果有兴趣的同学可以邮件本人,并一起参与中文笔记的撰文。转载的朋友请注明来源,非常感谢。
这份笔记围绕Python下的机器学习实践一共探讨四个方面的内容:监督学习、无监督学习、特征和模型的选取 和 几个流行的强力模型包的使用。
我特别喜欢用几句话对某些东西做个总结,对于 Kaggle 的任务,我个人觉得大体需要这么几个固定的机器学习流程(不包括决定性的分析),如果按照这个流程,采用 scikit-learn & pandas 包的话,普遍都会进 Top25%:
- pandas 读取 csv or tsv (Kaggle 上的数据基本都比较整洁)
- 特征少的话,补全数据,feature_extraction (DictVec, tfidfVec等等,根据数据类型而异,文本,图像,音频,这些处理方式都不同), feature_selection, grid_searching the best hyperparameters (model_selection), ensemble learning (或者综合好多学习器的结果), predict 或者 proba_predict (取决于任务的提交要求,是直接分类结果,还是分类概率,这个区别很大)。
- 特征多的话,补全数据,feature_extraction (DictVec, tfidfVec等等,根据数据类型而异,文本,图像,音频,这些处理方式都不同), 数据降维度(PCA,RBM等等),feature_selection (如果降维度之后还有必要), ensemble learning (或者综合好多学习器的结果), predict 或者 proba_predict (取决于任务的提交要求,是直接分类结果,还是分类概率,这个区别很大)。
1.监督学习
1.1 线性分类器
使用 Scikit-learn 数据库中预装的牵牛花品种数据,进行线性分类实践。线性分类器中,Logistic Regression 比较常用,适合做概率估计,即对分配给每个类别一个估计概率。这个在Kaggle竞赛里经常需要。
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
# 读取数据
iris = load_iris()
# 选取特征与标签
X_iris, y_iris = iris.data, iris.target
# 选择前两列数据作为特征
X, y = X_iris[:, :2], y_iris
# 选取一部分, 25% 的训练数据作为测试集
X_train, X_test, y_train, y_test = train_test_split(X, y,
test_size=0.25, random_state = 33)
# 对原特征数据进行标准化预处理,这个其实挺重要,但是经常被一些选手忽略
scaler = preprocessing.StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
from sklearn.linear_model import SGDClassifier
# 选择使用SGD分类器,适合大规模数据,随机梯度下降方法估计参数
clf = SGDClassifier()
clf.fit(X_train, y_train)
# 导入评价包
from sklearn import metrics
y_train_predict = clf.predict(X_train)
# 内测,使用训练样本进行准确性能评估
print(metrics.accuracy_score(y_train, y_train_predict))
# 标准外测,使用测试样本进行准确性能评估
y_predict = clf.predict(X_test)
print(metrics.accuracy_score(y_test, y_predict))
0.7678571428571429
0.7105263157894737
# 如果需要更加详细的性能报告,比如precision, recall, accuracy,可以使用如下的函数。
print(metrics.classification_report(y_test, y_predict, target_names = iris.target_names))
precision recall f1-score support
setosa 1.00 1.00 1.00 8
versicolor 0.50 0.09 0.15 11
virginica 0.64 0.95 0.77 19
accuracy 0.71 38
macro avg 0.71 0.68 0.64 38
weighted avg 0.68 0.71 0.64 38
# 如果想详细探查SGDClassifier的分类性能,我们需要充分利用数据,
# 因此需要把数据切分为N个部分,每个部分都用于测试一次模型性能。
from sklearn.model_selection import cross_val_score, KFold
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
# 这里使用Pipeline,便于精简模型搭建,一般而言,模型在fit之前,
# 对数据需要feature_extraction, preprocessing, 等必要步骤。
# 这里我们使用默认的参数配置
clf = Pipeline([('scaler', StandardScaler()), ('sgd_classifier', SGDClassifier())])
# 5折交叉验证整个数据集合
cv = KFold(n_splits=5, shuffle=True, random_state = 33)
scores = cross_val_score(clf, X, y, cv=cv)
print('Scores:')
print(scores)
print('---------------------------')
# 计算一下模型综合性能,平均精度和标准差
print('Scores_Mean Scores_Std')
print(' {} {}'.format(scores.mean(), scores.std()))
print('---------------------------')
from scipy.stats import sem
import numpy as np
# 这里使用的偏差计算函数略有不同,参考链接
# http://www.graphpad.com/guides/prism/6/statistics/index.htm?stat_semandsdnotsame.htm
print(np.mean(scores), sem(scores))
Scores:
[0.73333333 0.7 0.7 0.86666667 0.83333333]
---------------------------
Scores_Mean Scores_Std
0.7666666666666666 0.06992058987801014
---------------------------
0.7666666666666666 0.03496029493900507
总结一下:线性分类器有几种, Logistic_regression在scikit-learn里也有实现。比起SGD这个分类器而言,前者使用更加精确,但是更加耗时的解析解。SGD分类器可以大体代表这些线性分类器的性能,但是由于是近似估计的参数,因此模型性能结果不是很稳定,需要通过调节超参数获得模型的性能上限。
1.2 SVM 分类器
这一部分,我们探究支持向量机,这是个强分类器,性能要比普通线性分类器强大一些,一般而言,基于的也是线性假设。但是由于可以引入一些核技巧(kernel trick),可以将特征映射到更加高维度,甚至非线性的空间上,从而使数据空间变得更加可分。再加上SVM本身只是会选取少量的支持向量作为确定分类器超平面的证据,因此,即便数据变得高维度,非线性映射,也不会占用太多的内存空间,只是计算这些支持向量的CPU代价比较高。另外,这个分类器适合于直接做分类,不适合做分类概率的估计。
这里我们使用 AT&T 400张人脸,这个经典数据集来介绍:
from sklearn.datasets import fetch_olivetti_faces
# 这部分数据没有直接存储在现有包中,都是通过这类函数在线下载
faces = fetch_olivetti_faces()
downloading Olivetti faces from https://ndownloader.figshare.com/files/5976027 to
C:\Users\Administrator\scikit_learn_data
# 这里证明,数据是以Dict的形式存储的,与多数实验性数据的格式一致
faces.keys()
dict_keys(['data', 'images', 'target', 'DESCR'])
# 使用shape属性检验数据规模
print(faces.data.shape)
print(faces.target.shape)
(400, 4096)
(400,)
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
# 同样是分割数据 25%用于测试
X_train, X_test, y_train, y_test = train_test_split(
faces.data, faces.target, test_size=0.25, random_state=0)
from sklearn.model_selection import cross_val_score, KFold
from scipy.stats import sem
# 构造一个便于交叉验证模型性能的函数(模块)
def evaluate_cross_validation(clf, X, y, K):
# KFold 函数需要如下参数:数据量, 叉验次数, 是否洗牌
cv = KFold(K, shuffle=True, random_state = 0)
# 采用上述的分隔方式进行交叉验证,测试模型性能,对于分类问题,
# 这些得分默认是accuracy,也可以修改为别的
scores = cross_val_score(clf, X, y, cv=cv)
print(scores)
print('Mean score: %.3f (+/-%.3f)' % (scores.mean(), sem(scores)))
# 使用线性核的SVC (后面会说到不同的核,结果可能大不相同)
svc_linear = SVC(kernel='linear')
# 五折交叉验证 K = 5
evaluate_cross_validation(svc_linear, X_train, y_train, 5)
[0.93333333 0.86666667 0.91666667 0.93333333 0.91666667]
Mean score: 0.913 (+/-0.012)
1.3 朴素贝叶斯分类器(Naive Bayes)
这一部分我们探讨朴素贝叶斯分类器,大量实验证明,这个分类模型在对文本分类中能表现良好。究其原因,也许是对于邮件过滤这类任务,我们用于区分类别的文本特征彼此独立性较强,刚好模型的假设便是特征独立。
2.无监督学习
3.特征、模型的选择(高级话题)
4.强力(流行)模型包的尝试(高级话题)
这个话题有几个独立的部分,对于Xgboost和Tensorflow的试验,需要Linux环境。待回国后用IMAC试试:)。
不过仍然有一份高级一点的NLP相关的内容可以探讨,其中就有Kaggle上面利用Word2Vec对情感分析任务助益的项目。我们这里先来分析一下。
https://www.kaggle.com/c/word2vec-nlp-tutorial