【转】机器学习算法一览,应用建议与解决思路

1.引言

提起笔来写这篇博客,忽然有点愧疚和尴尬。愧疚的是,工做琐事多,加之懒癌严重,致使这个系列一直没有更新,向关注该系列的同窗们道个歉。尴尬的是,按理说,机器学习介绍与算法一览应该放在最前面写,详细的应用建议应该在讲完机器学习经常使用算法以后写,忽然莫名奇妙在中间插播这么一篇,好像有点打乱主线。 
老话说『亡羊补牢,为时未晚』,前面开头忘讲的东西,咱在这块儿补上。咱们先带着你们过一遍传统机器学习算法,基本思想和用途。把问题解决思路和方法应用建议提早到这里的想法也很简单,但愿能提早给你们一些小建议,对于某些容易出错的地方也先给你们打个预防针,这样在理解后续相应机器学习算法以后,使用起来也有必定的章法。html

2.机器学习算法简述

按照不一样的分类标准,能够把机器学习的算法作不一样的分类。python

2.1 从机器学习问题角度分类

咱们先从机器学习问题自己分类的角度来看,咱们能够分红下列类型的算法:git

  • 监督学习算法

机器学习中有一大部分的问题属于『监督学习』的范畴,简单口语化地说明,这类问题中,给定的训练样本中,每一个样本的输入xx都对应一个肯定的结果yy,咱们须要训练出一个模型(数学上看是一个xyx→y的映射关系ff),在未知的样本xx′给定后,咱们能对结果yy′作出预测。算法

这里的预测结果若是是离散值(不少时候是类别类型,好比邮件分类问题中的垃圾邮件/普通邮件,好比用户会/不会购买某商品),那么咱们把它叫作分类问题(classification problem);若是预测结果是连续值(好比房价,股票价格等等),那么咱们把它叫作回归问题(regression problem)。markdown

有一系列的机器学习算法是用以解决监督学习问题的,好比最经典的用于分类问题的朴素贝叶斯、逻辑回归、支持向量机等等;好比说用于回归问题的线性回归等等。网络

  • 无监督学习

有另一类问题,给咱们的样本并无给出『标签/标准答案』,就是一系列的样本。而咱们须要作的事情是,在一些样本中抽取出通用的规则。这叫作『无监督学习』。包括关联规则和聚类算法在内的一系列机器学习算法都属于这个范畴。数据结构

  • 半监督学习

这类问题给出的训练数据,有一部分有标签,有一部分没有标签。咱们想学习出数据组织结构的同时,也能作相应的预测。此类问题相对应的机器学习算法有自训练(Self-Training)、直推学习(Transductive Learning)、生成式模型(Generative Model)等。app

整体说来,最多见是前两类问题,而对应前两类问题的一些机器学习算法以下:dom

机器学习算法

2.2 从算法的功能角度分类

咱们也能够从算法的共性(好比功能,运做方式)角度对机器学习算法分类。下面咱们根据算法的共性去对它们归个类。不过须要注意的是,咱们下面的归类方法可能对分类和回归有比较强的倾向性,而这两类问题也是最常遇到的。机器学习

2.2.1 回归算法(Regression Algorithms)

 


回归算法 

回归算法是一种经过最小化预测值与实际结果值之间的差距,而获得输入特征之间的最佳组合方式的一类算法。对于连续值预测有线性回归等,而对于离散值/类别预测,咱们也能够把逻辑回归等也视做回归算法的一种,常见的回归算法以下:

 

  • Ordinary Least Squares Regression (OLSR)
  • Linear Regression
  • Logistic Regression
  • Stepwise Regression
  • Locally Estimated Scatterplot Smoothing (LOESS)
  • Multivariate Adaptive Regression Splines (MARS)

2.2.2 基于实例的算法(Instance-based Algorithms)

 


基于实例的算法 

这里所谓的基于实例的算法,我指的是咱们最后建成的模型,对原始数据样本实例依旧有很强的依赖性。这类算法在作预测决策时,通常都是使用某类类似度准则,去比对待预测的样本和原始样本的相近度,再给出相应的预测结果。常见的基于实例的算法有:

 

  • k-Nearest Neighbour (kNN)
  • Learning Vector Quantization (LVQ)
  • Self-Organizing Map (SOM)
  • Locally Weighted Learning (LWL)

2.2.3 决策树类算法(Decision Tree Algorithms)

 


决策树类算法 

决策树类算法,会基于原始数据特征,构建一颗包含不少决策路径的树。预测阶段选择路径进行决策。常见的决策树算法包括:

 

  • Classification and Regression Tree (CART)
  • Iterative Dichotomiser 3 (ID3)
  • C4.5 and C5.0 (different versions of a powerful approach)
  • Chi-squared Automatic Interaction Detection (CHAID)
  • M5
  • Conditional Decision Trees

2.2.4 贝叶斯类算法(Bayesian Algorithms)

 


贝叶斯类算法 

这里说的贝叶斯类算法,指的是在分类和回归问题中,隐含使用了贝叶斯原理的算法。包括:

 

  • Naive Bayes
  • Gaussian Naive Bayes
  • Multinomial Naive Bayes
  • Averaged One-Dependence Estimators (AODE)
  • Bayesian Belief Network (BBN)
  • Bayesian Network (BN)

2.2.5 聚类算法(Clustering Algorithms)

 


聚类算法 

聚类算法作的事情是,把输入样本聚成围绕一些中心的『数据团』,以发现数据分布结构的一些规律。经常使用的聚类算法包括:

 

  • k-Means
  • Hierarchical Clustering
  • Expectation Maximisation (EM)

2.2.6 关联规则算法(Association Rule Learning Algorithms)

 


关联规则算法 

关联规则算法是这样一类算法:它试图抽取出,最能解释观察到的训练样本之间关联关系的规则,也就是获取一个事件和其余事件之间依赖或关联的知识,常见的关联规则算法有:

 

  • Apriori algorithm
  • Eclat algorithm

2.2.7 人工神经网络类算法(Artificial Neural Network Algorithms)

 


人工神经网络类算法 

这是受人脑神经元工做方式启发而构造的一类算法。须要提到的一点是,我把『深度学习』单拎出来了,这里说的人工神经网络偏向于更传统的感知算法,主要包括:

 

  • Perceptron
  • Back-Propagation
  • Radial Basis Function Network (RBFN)

2.2.8 深度学习(Deep Learning Algorithms)

 


深度学习 

深度学习是近年来很是火的机器学习领域,相对于上面列的人工神经网络算法,它一般状况下,有着更深的层次和更复杂的结构。有兴趣的同窗能够看看咱们另外一个系列 机器学习与计算机视觉,最多见的深度学习算法包括:

 

  • Deep Boltzmann Machine (DBM)
  • Deep Belief Networks (DBN)
  • Convolutional Neural Network (CNN)
  • Stacked Auto-Encoders

2.2.9 降维算法(Dimensionality Reduction Algorithms)

 


降维算法 

从某种程度上说,降维算法和聚类其实有点相似,由于它也在试图发现原始训练数据的固有结构,可是降维算法在试图,用更少的信息(更低维的信息)总结和描述出原始信息的大部份内容。 
有意思的是,降维算法通常在数据的可视化,或者是下降数据计算空间有很大的做用。它做为一种机器学习的算法,不少时候用它先处理数据,再灌入别的机器学习算法学习。主要的降维算法包括:

 

  • Principal Component Analysis (PCA)
  • Principal Component Regression (PCR)
  • Partial Least Squares Regression (PLSR)
  • Sammon Mapping
  • Multidimensional Scaling (MDS)
  • Linear Discriminant Analysis (LDA)
  • Mixture Discriminant Analysis (MDA)
  • Quadratic Discriminant Analysis (QDA)
  • Flexible Discriminant Analysis (FDA)

2.2.10 模型融合算法(Ensemble Algorithms)

 


模型融合算法 

严格意义上来讲,这不算是一种机器学习算法,而更像是一种优化手段/策略,它一般是结合多个简单的弱机器学习算法,去作更可靠的决策。拿分类问题举个例,直观的理解,就是单个分类器的分类是可能出错,不可靠的,可是若是多个分类器投票,那可靠度就会高不少。经常使用的模型融合加强方法包括:

 

  • Random Forest
  • Boosting
  • Bootstrapped Aggregation (Bagging)
  • AdaBoost
  • Stacked Generalization (blending)
  • Gradient Boosting Machines (GBM)
  • Gradient Boosted Regression Trees (GBRT)

2.3 机器学习算法使用图谱

scikit-learn做为一个丰富的python机器学习库,实现了绝大多数机器学习的算法,有至关多的人在使用,因而我这里很无耻地把machine learning cheat sheet for sklearn搬过来了,原文能够看这里。哈哈,既然讲机器学习,咱们就用机器学习的语言来解释一下,这是针对实际应用场景的各类条件限制,对scikit-learn里完成的算法构建的一颗决策树,每一组条件都是对应一条路径,能找到相对较为合适的一些解决方法,具体以下:

sklearn机器学习算法使用图谱

首先样本量若是很是少的话,其实全部的机器学习算法都没有办法从里面『学到』通用的规则和模式,so多弄点数据是王道。而后根据问题是有/无监督学习和连续值/离散值预测,分红了分类聚类回归维度约减四个方法类,每一个类里根据具体状况的不一样,又有不一样的处理方法。

3. 机器学习问题解决思路

上面带着代价蜻蜓点水过了一遍机器学习的若干算法,下面咱们试着总结总结在拿到一个实际问题的时候,若是着手使用机器学习算法去解决问题,其中的一些注意点以及核心思路。主要包括如下内容:

  • 拿到数据后怎么了解数据(可视化)
  • 选择最贴切的机器学习算法
  • 定位模型状态(过/欠拟合)以及解决方法
  • 大量极的数据的特征分析与可视化
  • 各类损失函数(loss function)的优缺点及如何选择

多说一句,这里写的这个小教程,主要是做为一个通用的建议和指导方案,你不必定要严格按照这个流程解决机器学习问题。

3.1 数据与可视化

咱们先使用scikit-learn的make_classification函数来生产一份分类数据,而后模拟一下拿到实际数据后咱们须要作的事情。

#numpy科学计算工具箱 import numpy as np #使用make_classification构造1000个样本,每一个样本有20个feature from sklearn.datasets import make_classification X, y = make_classification(1000, n_features=20, n_informative=2, n_redundant=2, n_classes=2, random_state=0) #存为dataframe格式 from pandas import DataFrame df = DataFrame(np.hstack((X, y[:, None])),columns = range(20) + ["class"])

 

咱们生成了一份包含1000个分类数据样本的数据集,每一个样本有20个数值特征。同时咱们把数据存储至pandas中的DataFrame数据结构中。咱们取前几行的数据看一眼: 


前6行

 

不幸的是,肉眼看数据,尤为是维度稍微高点的时候,颇有可能看花了也看不出看不出任何线索。幸运的是,咱们对于图像的理解力,比数字好太多,而又有至关多的工具能够帮助咱们『可视化』数据分布。

咱们在处理任何数据相关的问题时,了解数据都是颇有必要的,而可视化能够帮助咱们更好地直观理解数据的分布和特性

数据的可视化有不少工具包能够用,好比下面咱们用来作数据可视化的工具包Seaborn。最简单的可视化就是数据散列分布图和柱状图,这个能够用Seanborn的pairplot来完成。如下图中2种颜色表示2种不一样的类,由于20维的可视化没有办法在平面表示,咱们取出了一部分维度,两两组成pair看数据在这2个维度平面上的分布情况,代码和结果以下:

import matplotlib.pyplot as plt import seaborn as sns #使用pairplot去看不一样特征维度pair下数据的空间分布情况 _ = sns.pairplot(df[:50], vars=[8, 11, 12, 14, 19], hue="class", size=1.5) plt.show()

 


pair_plot下数据分布情况 

 

咱们从散列图和柱状图上能够看出,确实有些维度的特征相对其余维度,有更好的区分度,好比第11维和14维看起来颇有区分度。这两个维度上看,数据点是近似线性可分的。而12维和19维彷佛呈现出了很高的负相关性。接下来咱们用Seanborn中的corrplot来计算计算各维度特征之间(以及最后的类别)的相关性。代码和结果图以下:

import matplotlib.pyplot as plt plt.figure(figsize=(12, 10)) _ = sns.corrplot(df, annot=False) plt.show()

 


各位特征相关性 

 

相关性图很好地印证了咱们以前的想法,能够看到第11维特征和第14维特征和类别有极强的相关性,同时它们俩之间也有极高的相关性。而第12维特征和第19维特征却呈现出极强的负相关性。强相关的特征其实包含了一些冗余的特征,而除掉上图中颜色较深的特征,其他特征包含的信息量就没有这么大了,它们和最后的类别相关度不高,甚至各自之间也没什么先惯性。

插一句,这里的维度只有20,因此这个相关度计算并不费太大力气,然而实际情形中,你彻底有可能有远高于这个数字的特征维度,同时样本量也可能多不少,那种情形下咱们可能要先作一些处理,再来实现可视化了。别着急,一下子咱们会讲到。

3.2 机器学习算法选择

数据的状况咱们大体看了一眼,肯定一些特征维度以后,咱们能够考虑先选用机器学习算法作一个baseline的系统出来了。这里咱们继续参照上面提到过的机器学习算法使用图谱。 
咱们只有1000个数据样本,是分类问题,同时是一个有监督学习,所以咱们根据图谱里教的方法,使用LinearSVC(support vector classification with linear kernel)试试。注意,LinearSVC须要选择正则化方法以缓解过拟合问题;咱们这里选择使用最多的L2正则化,并把惩罚系数C设为10。咱们改写一下sklearn中的学习曲线绘制函数,画出训练集和交叉验证集上的得分:

from sklearn.svm import LinearSVC from sklearn.learning_curve import learning_curve #绘制学习曲线,以肯定模型的情况 def plot_learning_curve(estimator, title, X, y, ylim=None, cv=None, train_sizes=np.linspace(.1, 1.0, 5)): """ 画出data在某模型上的learning curve. 参数解释 ---------- estimator : 你用的分类器。 title : 表格的标题。 X : 输入的feature,numpy类型 y : 输入的target vector ylim : tuple格式的(ymin, ymax), 设定图像中纵坐标的最低点和最高点 cv : 作cross-validation的时候,数据分红的份数,其中一份做为cv集,其他n-1份做为training(默认为3份) """ plt.figure() train_sizes, train_scores, test_scores = learning_curve( estimator, X, y, cv=5, n_jobs=1, train_sizes=train_sizes) train_scores_mean = np.mean(train_scores, axis=1) train_scores_std = np.std(train_scores, axis=1) test_scores_mean = np.mean(test_scores, axis=1) test_scores_std = np.std(test_scores, axis=1) plt.fill_between(train_sizes, train_scores_mean - train_scores_std, train_scores_mean + train_scores_std, alpha=0.1, color="r") plt.fill_between(train_sizes, test_scores_mean - test_scores_std, test_scores_mean + test_scores_std, alpha=0.1, color="g") plt.plot(train_sizes, train_scores_mean, 'o-', color="r", label="Training score") plt.plot(train_sizes, test_scores_mean, 'o-', color="g", label="Cross-validation score") plt.xlabel("Training examples") plt.ylabel("Score") plt.legend(loc="best") plt.grid("on") if ylim: plt.ylim(ylim) plt.title(title) plt.show() #少样本的状况状况下绘出学习曲线 plot_learning_curve(LinearSVC(C=10.0), "LinearSVC(C=10.0)", X, y, ylim=(0.8, 1.01), train_sizes=np.linspace(.05, 0.2, 5))

 


学习曲线1 

 

这幅图上,咱们发现随着样本量的增长,训练集上的得分有必定程度的降低,交叉验证集上的得分有必定程度的上升,但整体说来,二者之间有很大的差距,训练集上的准确度远高于交叉验证集。这其实意味着咱们的模型处于过拟合的状态,也即模型太努力地刻画训练集,一不当心把不少噪声的分布也拟合上了,致使在新数据上的泛化能力变差了。

3.2.1 过拟合的定位与解决

问题来了,过拟合咋办? 
针对过拟合,有几种办法能够处理:

  • 增大样本量

这个比较好理解吧,过拟合的主要缘由是模型太努力地去记住训练样本的分布情况,而加大样本量,可使得训练集的分布更加具有普适性,噪声对总体的影响降低。恩,咱们提升点样本量试试:

#增大一些样本量 plot_learning_curve(LinearSVC(C=10.0), "LinearSVC(C=10.0)", X, y, ylim=(0.8, 1.1), train_sizes=np.linspace(.1, 1.0, 5))

 

 


学习曲线2 

 

是否是发现问题好了不少?随着咱们增大训练样本量,咱们发现训练集和交叉验证集上的得分差距在减小,最后它们已经很是接近了。增大样本量,最直接的方法固然是想办法去采集相同场景下的新数据,若是实在作不到,也能够试试在已有数据的基础上作一些人工的处理生成新数据(好比图像识别中,咱们可能能够对图片作镜像变换、旋转等等),固然,这样作必定要谨慎,强烈建议想办法采集真实数据。

  • 减小特征的量(只用咱们以为有效的特征)

好比在这个例子中,咱们以前的数据可视化和分析的结果代表,第11和14维特征包含的信息对识别类别很是有用,咱们能够只用它们。

plot_learning_curve(LinearSVC(C=10.0), "LinearSVC(C=10.0) Features: 11&14", X[:, [11, 14]], y, ylim=(0.8, 1.0), train_sizes=np.linspace(.05, 0.2, 5))

 


特征选择后 

 

从上图上能够看出,过拟合问题也获得必定程度的缓解。不过咱们这是本身观察后,手动选出11和14维特征。那能不能自动进行特征组合和选择呢,其实咱们固然能够遍历特征的组合样式,而后再进行特征选择(前提依旧是这里特征的维度不高,若是高的话,遍历全部的组合是一个很是很是很是耗时的过程!!):

from sklearn.pipeline import Pipeline from sklearn.feature_selection import SelectKBest, f_classif # SelectKBest(f_classif, k=2) 会根据Anova F-value选出 最好的k=2个特征 plot_learning_curve(Pipeline([("fs", SelectKBest(f_classif, k=2)), # select two features ("svc", LinearSVC(C=10.0))]), "SelectKBest(f_classif, k=2) + LinearSVC(C=10.0)", X, y, ylim=(0.8, 1.0), train_sizes=np.linspace(.05, 0.2, 5))

 

 


自动特征选择 

 

若是你本身跑一下程序,会发如今咱们本身手造的这份数据集上,这个特征筛选的过程超级顺利,但依旧像咱们以前提过的同样,这是由于特征的维度不过高。 
从另一个角度看,咱们之因此作特征选择,是想下降模型的复杂度,而更不容易刻画到噪声数据的分布。从这个角度出发,咱们还能够有(1)多项式你和模型中下降多项式次数 (2)神经网络中减小神经网络的层数和每层的结点数 (c)SVM中增长RBF-kernel的bandwidth等方式来下降模型的复杂度。 
话说回来,即便以上提到的办法下降模型复杂度后,好像能在必定程度上缓解过拟合,可是咱们通常仍是不建议一遇到过拟合,就用这些方法处理,优先用下面的方法:

  • 加强正则化做用(好比说这里是减少LinearSVC中的C参数) 
    正则化是我认为在不损失信息的状况下,最有效的缓解过拟合现象的方法。
plot_learning_curve(LinearSVC(C=0.1), "LinearSVC(C=0.1)", X, y, ylim=(0.8, 1.0), train_sizes=np.linspace(.05, 0.2, 5))

 


调整正则化参数 

 

调整正则化系数后,发现确实过拟合现象有必定程度的缓解,但依旧是那个问题,咱们如今的系数是本身敲定的,有没有办法能够自动选择最佳的这个参数呢?能够。咱们能够在交叉验证集上作grid-search查找最好的正则化系数(对于大数据样本,咱们依旧须要考虑时间问题,这个过程可能会比较慢):

from sklearn.grid_search import GridSearchCV estm = GridSearchCV(LinearSVC(), param_grid={"C": [0.001, 0.01, 0.1, 1.0, 10.0]}) plot_learning_curve(estm, "LinearSVC(C=AUTO)", X, y, ylim=(0.8, 1.0), train_sizes=np.linspace(.05, 0.2, 5)) print "Chosen parameter on 100 datapoints: %s" % estm.fit(X[:500], y[:500]).best_params_

 

在500个点获得的结果是:{‘C’: 0.01} 
使用新的C参数,咱们再看看学习曲线: 


C取0.01的学习曲线 

 

对于特征选择的部分,我打算多说几句,咱们刚才看过了用sklearn.feature_selection中的SelectKBest来选择特征的过程,也提到了在高维特征的状况下,这个过程可能会很是很是慢。那咱们有别的办法能够进行特征选择吗?好比说,咱们的分类器本身可否甄别那些特征是对最后的结果有益的?这里有个实际工做中用到的小技巧。

咱们知道:

  • l2正则化,它对于最后的特征权重的影响是,尽可能打散权重到每一个特征维度上,不让权重集中在某些维度上,出现权重特别高的特征。
  • 而l1正则化,它对于最后的特征权重的影响是,让特征得到的权重稀疏化,也就是对结果影响不那么大的特征,干脆就拿不着权重。

那基于这个理论,咱们能够把SVC中的正则化替换成l1正则化,让其自动甄别哪些特征应该留下权重。

plot_learning_curve(LinearSVC(C=0.1, penalty='l1', dual=False), "LinearSVC(C=0.1, penalty='l1')", X, y, ylim=(0.8, 1.0), train_sizes=np.linspace(.05, 0.2, 5))

 

 


使用l1正则化 

 

好了,咱们一块儿来看看最后特征得到的权重:

estm = LinearSVC(C=0.1, penalty='l1', dual=False) estm.fit(X[:450], y[:450]) # 用450个点来训练 print "Coefficients learned: %s" % est.coef_ print "Non-zero coefficients: %s" % np.nonzero(estm.coef_)[1]

 

获得结果:

Coefficients learned: [[ 0. 0. 0. 0. 0. 0.01857999 0. 0. 0. 0.004135 0. 1.05241369 0.01971419 0. 0. 0. 0. -0.05665314 0.14106505 0. ]] Non-zero coefficients: [5 9 11 12 17 18]

 

你看,5 9 11 12 17 18这些维度的特征得到了权重,而第11维权重最大,也说明了它影响程度最大。

3.2.2 欠拟合定位与解决

咱们再随机生成一份数据[1000*20]的数据(可是分布和以前有变化),从新使用LinearSVC来作分类。

#构造一份环形数据 from sklearn.datasets import make_circles X, y = make_circles(n_samples=1000, random_state=2) #绘出学习曲线 plot_learning_curve(LinearSVC(C=0.25),"LinearSVC(C=0.25)",X, y, ylim=(0.5, 1.0),train_sizes=np.linspace(.1, 1.0, 5))

 

 


环形数据的学习曲线 

 

简直烂出翔了有木有,二分类问题,咱们作随机猜想,准确率都有0.5,这比随机猜想都高不了多少!!!怎么办?

不要盲目动手收集更多资料,或者调整正则化参数。咱们从学习曲线上其实能够看出来,训练集上的准确度和交叉验证集上的准确度都很低,这其实就对应了咱们说的『欠拟合』状态。别急,咱们回到咱们的数据,仍是可视化看看:

f = DataFrame(np.hstack((X, y[:, None])), columns = range(2) + ["class"]) _ = sns.pairplot(df, vars=[0, 1], hue="class", size=3.5)

 

 


环形数据可视化 

 

你发现什么了,数据根本就没办法线性分割!!!,因此你再找更多的数据,或者调整正则化参数,都是无济于事的!!!

那咱们又怎么解决欠拟合问题呢?一般有下面一些方法:

  • 调整你的特征(找更有效的特征!!) 
    好比说咱们观察完如今的数据分布,而后咱们先对数据作个映射:
# 加入原始特征的平方项做为新特征 X_extra = np.hstack((X, X[:, [0]]**2 + X[:, [1]]**2)) plot_learning_curve(LinearSVC(C=0.25), "LinearSVC(C=0.25) + distance feature", X_extra, y, ylim=(0.5, 1.0), train_sizes=np.linspace(.1, 1.0, 5))

 

 


平方映射后的准确度 

卧槽,少年,这准确率,被吓尿了有木有啊!!!因此你看,选用的特征影响太大了,固然,咱们这里是人工模拟出来的数据,分布太明显了,实际数据上,会比这个麻烦一些,可是在特征上面下的功夫仍是颇有回报的。

 

  • 使用更复杂一点的模型(好比说用非线性的核函数) 
    咱们对模型稍微调整了一下,用了一个复杂一些的非线性rbf kernel:
from sklearn.svm import SVC # note: we use the original X without the extra feature plot_learning_curve(SVC(C=2.5, kernel="rbf", gamma=1.0), "SVC(C=2.5, kernel='rbf', gamma=1.0)",X, y, ylim=(0.5, 1.0), train_sizes=np.linspace(.1, 1.0, 5))

 

 


rbf核SVM学习曲线 

 

你看,效果依旧很赞。

3.3 关于大数据样本集和高维特征空间

咱们在小样本的toy dataset上,怎么捣鼓都有好的方法。可是当数据量和特征样本空间膨胀很是厉害时,不少东西就没有那么好使了,至少是一个很耗时的过程。举个例子说,咱们如今从新生成一份数据集,可是此次,咱们生成更多的数据,更高的特征维度,而分类的类别也提升到5。

3.3.1 大数据情形下的模型选择与学习曲线

在上面提到的那样一份数据上,咱们用LinearSVC可能就会有点慢了,咱们注意到机器学习算法使用图谱推荐咱们使用SGDClassifier。其实本质上说,这个模型也是一个线性核函数的模型,不一样的地方是,它使用了随机梯度降低作训练,因此每次并无使用所有的样本,收敛速度会快不少。再多提一点,SGDClassifier对于特征的幅度很是敏感,也就是说,咱们在把数据灌给它以前,应该先对特征作幅度调整,固然,用sklearn的StandardScaler能够很方便地完成这一点。

SGDClassifier每次只使用一部分(mini-batch)作训练,在这种状况下,咱们使用交叉验证(cross-validation)并非很合适,咱们会使用相对应的progressive validation:简单解释一下,estimator每次只会拿下一个待训练batch在本次作评估,而后训练完以后,再在这个batch上作一次评估,看看是否有优化。

#生成大样本,高纬度特征数据 X, y = make_classification(200000, n_features=200, n_informative=25, n_redundant=0, n_classes=10, class_sep=2, random_state=0) #用SGDClassifier作训练,并画出batch在训练先后的得分差 from sklearn.linear_model import SGDClassifier est = SGDClassifier(penalty="l2", alpha=0.001) progressive_validation_score = [] train_score = [] for datapoint in range(0, 199000, 1000): X_batch = X[datapoint:datapoint+1000] y_batch = y[datapoint:datapoint+1000] if datapoint > 0: progressive_validation_score.append(est.score(X_batch, y_batch)) est.partial_fit(X_batch, y_batch, classes=range(10)) if datapoint > 0: train_score.append(est.score(X_batch, y_batch)) plt.plot(train_score, label="train score") plt.plot(progressive_validation_score, label="progressive validation score") plt.xlabel("Mini-batch") plt.ylabel("Score") plt.legend(loc='best') plt.show() 

 

获得以下的结果: 


SGDClassifier学习曲线 

 

从这个图上的得分,咱们能够看出在50个mini-batch迭代以后,数据上的得分就已经变化不大了。可是好像得分都不过高,因此咱们猜想一下,这个时候咱们的数据,处于欠拟合状态。咱们刚才在小样本集合上提到了,若是欠拟合,咱们可使用更复杂的模型,好比把核函数设置为非线性的,但遗憾的是像rbf核函数是没有办法和SGDClassifier兼容的。所以咱们只能想别的办法了,好比这里,咱们能够把SGDClassifier整个替换掉了,用多层感知神经网来完成这个任务,咱们之因此会想到多层感知神经网,是由于它也是一个用随机梯度降低训练的算法,同时也是一个非线性的模型。固然根据机器学习算法使用图谱,也可使用核估计(kernel-approximation)来完成这个事情。

3.3.2 大数据量下的可视化

大样本数据的可视化是一个相对比较麻烦的事情,通常状况下咱们都要用到降维的方法先处理特征。咱们找一个例子来看看,能够怎么作,好比咱们数据集取经典的『手写数字集』,首先找个方法看一眼这个图片数据集。

#直接从sklearn中load数据集 from sklearn.datasets import load_digits digits = load_digits(n_class=6) X = digits.data y = digits.target n_samples, n_features = X.shape print "Dataset consist of %d samples with %d features each" % (n_samples, n_features) # 绘制数字示意图 n_img_per_row = 20 img = np.zeros((10 * n_img_per_row, 10 * n_img_per_row)) for i in range(n_img_per_row): ix = 10 * i + 1 for j in range(n_img_per_row): iy = 10 * j + 1 img[ix:ix + 8, iy:iy + 8] = X[i * n_img_per_row + j].reshape((8, 8)) plt.imshow(img, cmap=plt.cm.binary) plt.xticks([]) plt.yticks([]) _ = plt.title('A selection from the 8*8=64-dimensional digits dataset') plt.show()

 

 


数字示意图 

 

咱们总共有1083个训练样本,包含手写数字(0,1,2,3,4,5),每一个样本图片中的像素点平铺开都是64位,这个维度显然是没办法直接可视化的。下面咱们基于scikit-learn的示例教程对特征用各类方法作降维处理,再可视化。

随机投射 
咱们先看看,把数据随机投射到两个维度上的结果:

#import所需的package from sklearn import (manifold, decomposition, random_projection) rp = random_projection.SparseRandomProjection(n_components=2, random_state=42) #定义绘图函数 from matplotlib import offsetbox def plot_embedding(X, title=None): x_min, x_max = np.min(X, 0), np.max(X, 0) X = (X - x_min) / (x_max - x_min) plt.figure(figsize=(10, 10)) ax = plt.subplot(111) for i in range(X.shape[0]): plt.text(X[i, 0], X[i, 1], str(digits.target[i]), color=plt.cm.Set1(y[i] / 10.), fontdict={'weight': 'bold', 'size': 12}) if hasattr(offsetbox, 'AnnotationBbox'): # only print thumbnails with matplotlib > 1.0 shown_images = np.array([[1., 1.]]) # just something big for i in range(digits.data.shape[0]): dist = np.sum((X[i] - shown_images) ** 2, 1) if np.min(dist) < 4e-3: # don't show points that are too close continue shown_images = np.r_[shown_images, [X[i]]] imagebox = offsetbox.AnnotationBbox( offsetbox.OffsetImage(digits.images[i], cmap=plt.cm.gray_r), X[i]) ax.add_artist(imagebox) plt.xticks([]), plt.yticks([]) if title is not None: plt.title(title) #记录开始时间 start_time = time.time() X_projected = rp.fit_transform(X) plot_embedding(X_projected, "Random Projection of the digits (time: %.3fs)" % (time.time() - start_time))

 

结果以下: 


2方向随机投射图 

 

PCA降维 
在维度约减/降维领域有一个很是强大的算法叫作PCA(Principal Component Analysis,主成分分析),它能将原始的绝大多数信息用维度远低于原始维度的几个主成分表示出来。PCA在咱们如今的数据集上效果还不错,咱们来看看用PCA对原始特征降维至2维后,原始样本在空间的分布情况:

from sklearn import (manifold, decomposition, random_projection) #TruncatedSVD 是 PCA的一种实现 X_pca = decomposition.TruncatedSVD(n_components=2).fit_transform(X) #记录时间 start_time = time.time() plot_embedding(X_pca,"Principal Components projection of the digits (time: %.3fs)" % (time.time() - start_time))

获得的结果以下: 


PCA后的可视化 

 

咱们能够看出,效果还不错,不一样的手写数字在2维平面上,显示出了区域集中性。即便它们之间有必定的重叠区域。

若是咱们用一些非线性的变换来作降维操做,从原始的64维降到2维空间,效果更好,好比这里咱们用到一个技术叫作t-SNE,sklearn的manifold对其进行了实现:

from sklearn import (manifold, decomposition, random_projection) #降维 tsne = manifold.TSNE(n_components=2, init='pca', random_state=0) start_time = time.time() X_tsne = tsne.fit_transform(X) #绘图 plot_embedding(X_tsne, "t-SNE embedding of the digits (time: %.3fs)" % (time.time() - start_time))

 

 


非线性降维手写数字分布图 

 

咱们发现结果很是的惊人,彷佛这个非线性变换降维事后,仅仅2维的特征,就能够将原始数据的不一样类别,在平面上很好地划分开。不过t-SNE也有它的缺点,通常说来,相对于线性变换的降维,它须要更多的计算时间。也不太适合在大数据集上全集使用。

3.4 损失函数的选择

损失函数的选择对于问题的解决和优化,很是重要。咱们先来看一眼各类不一样的损失函数:

import numpy as np import matplotlib.plot as plt # 改自http://scikit-learn.org/stable/auto_examples/linear_model/plot_sgd_loss_functions.html xmin, xmax = -4, 4 xx = np.linspace(xmin, xmax, 100) plt.plot([xmin, 0, 0, xmax], [1, 1, 0, 0], 'k-', label="Zero-one loss") plt.plot(xx, np.where(xx < 1, 1 - xx, 0), 'g-', label="Hinge loss") plt.plot(xx, np.log2(1 + np.exp(-xx)), 'r-', label="Log loss") plt.plot(xx, np.exp(-xx), 'c-', label="Exponential loss") plt.plot(xx, -np.minimum(xx, 0), 'm-', label="Perceptron loss") plt.ylim((0, 8)) plt.legend(loc="upper right") plt.xlabel(r"Decision function $f(x)$") plt.ylabel("$L(y, f(x))$") plt.show()

 

获得结果图像以下:

 


损失函数对比 

 

不一样的损失函数有不一样的优缺点:

  • 0-1损失函数(zero-one loss)很是好理解,直接对应分类问题中判断错的个数。可是比较尴尬的是它是一个非凸函数,这意味着其实不是那么实用。
  • hinge loss(SVM中使用到的)的健壮性相对较高(对于异常点/噪声不敏感)。可是它没有那么好的几率解释。
  • log损失函数(log-loss)的结果能很是好地表征几率分布。所以在不少场景,尤为是多分类场景下,若是咱们须要知道结果属于每一个类别的置信度,那这个损失函数很适合。缺点是它的健壮性没有那么强,相对hinge loss会对噪声敏感一些。
  • 多项式损失函数(exponential loss)(AdaBoost中用到的)对离群点/噪声很是很是敏感。可是它的形式对于boosting算法简单而有效。
  • 感知损失(perceptron loss)能够看作是hinge loss的一个变种。hinge loss对于断定边界附近的点(正确端)惩罚力度很高。而perceptron loss,只要样本的断定类别结果是正确的,它就是满意的,而无论其离断定边界的距离。优势是比hinge loss简单,缺点是由于不是max-margin boundary,因此获得模型的泛化能力没有hinge loss强。

4. 总结

全文到此就结束了。先蜻蜓点水看了一遍机器学习的算法,而后给出了对应scikit-learn的『秘密武器』机器学习算法使用图谱,紧接着从了解数据(可视化)、选择机器学习算法、定位过/欠拟合及解决方法、大量极的数据可视化和损失函数优缺点与选择等方面介绍了实际机器学习问题中的一些思路和方法。本文和文章机器学习系列(3)_逻辑回归应用之Kaggle泰坦尼克之灾都说起了一些处理实际机器学习问题的思路和方法,有类似和互补之处,欢迎你们参照着看。

 
转自:https://blog.csdn.net/han_xiaoyang/article/details/50469334
相关文章
相关标签/搜索