一般流程:数据收集、整理→数据预处理与特征工程(数据清理、集成、规约、变换、特征提取、筛选)→模型的选择与建立→模型的评估与优化。
数据集拆分
在得到训练数据集时,经常会把训练数据进一步拆分成训练集和验证集,这样有助于模型参数的选取。train_test_split是交叉验证中常用的函数,功能是从样本中随机的按比例选取train data和testdata,形式为
from sklearn.mode_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
- train_data:所要划分的样本特征集
- train_target:所要划分的样本结果
- test_size:样本占比,如果是整数的话就是样本的数量
- random_state:是随机数的种子。
- 随机数种子(random_state):其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的随机数。比如你每次都填1,其他参数一样的情况下你得到的随机数组是一样的。但填0或不填,每次都会不一样。
- 随机数的产生取决于种子,随机数和种子之间的关系遵从以下两个规则:种子不同,产生不同的随机数;种子相同,即使实例不同也产生相同的随机数
模型的选择与建立
根据算法选择路径图:
由图中,可以看到库的算法主要有四类:分类,回归,聚类,降维。其中:
- 常用的回归:线性、逻辑、决策树、SVM、KNN ;集成回归:随机森林、Adaboost、GradientBoosting、Bagging、ExtraTrees
- 常用的分类:线性、决策树、SVM、KNN,朴素贝叶斯;集成分类:随机森林、Adaboost、GradientBoosting、Bagging、ExtraTrees
- 常用聚类:k均值(K-means)、层次聚类(Hierarchical clustering)、DBSCAN
- 常用降维:LinearDiscriminantAnalysis、PCA
根据上图选择好所需的算法后,就可以在sklearn中定义模型了,sklearn为所有模型提供了非常相似的接口,可以更加快速的熟悉所有模型的用法,模型的常用属性和功能如下:
# 拟合模型
model.fit(X_train, y_train)
# 模型预测
model.predict(X_test)
# 获得这个模型的参数
model.get_params()
# 为模型进行打分
model.score(data_X, data_y)
# 所得数值
# 线性回归:R square(R方); 分类问题:acc
定义模型:
1.线性回归LinearRegression
模型全部是用鸢尾花数据集进行的测试。
from sklearn import datasets
iris = datasets.load_iris()
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
from sklearn.linear_model import LinearRegression
# 定义线性回归模型
model = LinearRegression(fit_intercept=True, normalize=False, copy_X=True, n_jobs=1)
- fit_intercept:是否有截据,如果没有则直线过原点;
- normalize:是否将数据归一化;
- copy_X:默认为True,当为True时,X会被copied,否则X将会被覆写;
- n_jobs:默认值为1。计算时使用的线程数。
- 优点:思想简单,实现容易。建模迅速,对于小数据量、简单的关系很有效;十分容易理解,结果具有很好的可解释性,有利于决策分析。
- 缺点:对于非线性数据或者数据特征间具有相关性多项式回归难以建模,难以很好地表达高度复杂的数据。
2.逻辑回归LogisticRegression
from sklearn.linear_model import LogisticRegression
# 定义逻辑回归模型
model = LogisticRegression(penalty='l2', dual=False, tol=0.0001, C=1.0, fit_intercept=True, intercept_scaling=1, class_weight=None, random_state=None, solver='liblinear', max_iter=100, multi_class='ovr', verbose=0, warm_start=False, n_jobs=1)
- penalty:惩罚项,str类型,可选参数为l1和l2,默认为l2。用于指定惩罚项中使用的规范。newton-cg、sag和lbfgs求解算法只支持L2规范。L1G规范假设的是模型的参数满足拉普拉斯分布,L2假设的模型参数满足高斯分布,所谓的范式就是加上对参数的约束,使得模型更不会过拟合(overfit),但是如果要说是不是加了约束就会好,这个没有人能回答,只能说,加约束的情况下,理论上应该可以获得泛化能力更强的结果。
- dual:对偶或原始方法,bool类型,默认为False。对偶方法只用在求解线性多核(liblinear)的L2惩罚项上。当样本数量>样本特征的时候,dual通常设置为False。
- tol:停止求解的标准,float类型,默认为1e-4。就是求解到多少的时候,停止,认为已经求出最优解。
- c:正则化系数λ的倒数,float类型,默认为1.0。必须是正浮点型数。像SVM一样,越小的数值表示越强的正则化。
- fit_intercept:是否存在截距或偏差,bool类型,默认为True。
- intercept_scaling:仅在正则化项为”liblinear”,且fit_intercept设置为True时有用。float类型,默认为1。
- class_weight:用于标示分类模型中各种类型的权重,可以是一个字典或者’balanced’字符串,默认为不输入,也就是不考虑权重,即为None。如果选择输入的话,可以选择balanced让类库自己计算类型权重,或者自己输入各个类型的权重。举个例子,比如对于0,1的二元模型,我们可以定义class_weight={0:0.9,1:0.1},这样类型0的权重为90%,而类型1的权重为10%。如果class_weight选择balanced,那么类库会根据训练样本量来计算权重。某种类型样本量越多,则权重越低,样本量越少,则权重越高。当class_weight为balanced时,类权重计算方法如下:n_samples / (n_classes * np.bincount(y))。n_samples为样本数,n_classes为类别数量,np.bincount(y)会输出每个类的样本数,例如y=[1,0,0,1,1],则np.bincount(y)=[2,3]。
class_weight的作用:在分类模型中,我们经常会遇到两类问题:
第一种是误分类的代价很高。比如对合法用户和非法用户进行分类,将非法用户分类为合法用户的代价很高,我们宁愿将合法用户分类为非法用户,这时可以人工再甄别,但是却不愿将非法用户分类为合法用户。这时,我们可以适当提高非法用户的权重。
第二种是样本是高度失衡的,比如我们有合法用户和非法用户的二元样本数据10000条,里面合法用户有9995条,非法用户只有5条,如果我们不考虑权重,则我们可以将所有的测试集都预测为合法用户,这样预测准确率理论上有99.95%,但是却没有任何意义。这时,我们可以选择balanced,让类库自动提高非法用户样本的权重。提高了某种分类的权重,相比不考虑权重,会有更多的样本分类划分到高权重的类别,从而可以解决上面两类问题。
- random_state:随机数种子,int类型,可选参数,默认为无,仅在正则化优化算法为sag,liblinear时有用。
- solver:优化算法选择参数,只有五个可选参数,即newton-cg,lbfgs,liblinear,sag,saga。默认为liblinear。solver参数决定了我们对逻辑回归损失函数的优化方法,有四种算法可以选择,分别是:
- liblinear:使用了开源的liblinear库实现,内部使用了坐标轴下降法来迭代优化损失函数。
- lbfgs:拟牛顿法的一种,利用损失函数二阶导数矩阵即海森矩阵来迭代优化损失函数。
- newton-cg:也是牛顿法家族的一种,利用损失函数二阶导数矩阵即海森矩阵来迭代优化损失函数。
- sag:即随机平均梯度下降,是梯度下降法的变种,和普通梯度下降法的区别是每次迭代仅仅用一部分的样本来计算梯度,适合于样本数据多的时候。
- saga:线性收敛的随机优化算法的的变重。
总结:
liblinear适用于小数据集,而sag和saga适用于大数据集因为速度更快。
对于多分类问题,只有newton-cg,sag,saga和lbfgs能够处理多项损失,而liblinear受限于一对剩余(OvR)。就是用liblinear的时候,如果是多分类问题,得先把一种类别作为一个类别,剩余的所有类别作为另外一个类别。一次类推,遍历所有类别,进行分类。
newton-cg,sag和lbfgs这三种优化算法时都需要损失函数的一阶或者二阶连续导数,因此不能用于没有连续导数的L1正则化,只能用于L2正则化。而liblinear和saga通吃L1正则化和L2正则化。
同时,sag每次仅仅使用了部分样本进行梯度迭代,所以当样本量少的时候不要选择它,而如果样本量非常大,比如大于10万,sag是第一选择。但是sag不能用于L1正则化,所以当你有大量的样本,又需要L1正则化的话就要自己做取舍了。要么通过对样本采样来降低样本量,要么回到L2正则化。
- max_iter:算法收敛最大迭代次数,int类型,默认为10。仅在正则化优化算法为newton-cg, sag和lbfgs才有用,算法收敛的最大迭代次数。
- multi_class:分类方式选择参数,str类型,可选参数为ovr和multinomial,默认为ovr。ovr即前面提到的one-vs-rest(OvR),而multinomial即前面提到的many-vs-many(MvM)。如果是二元逻辑回归,ovr和multinomial并没有任何区别,区别主要在多元逻辑回归上。
- verbose:日志冗长度,int类型。默认为0。就是不输出训练过程,1的时候偶尔输出结果,大于1,对于每个子模型都输出。
- warm_start:热启动参数,bool类型。默认为False。如果为True,则下一次训练是以追加树的形式进行(重新使用上一次的调用作为初始化)。
- n_jobs:并行数。int类型,默认为1。1的时候,用CPU的一个内核运行程序,2的时候,用CPU的2个内核运行程序。为-1的时候,用所有CPU的内核运行程序。
- 优点:实现简单,易于理解和实现;计算代价不高,速度很快,存储资源低。
- 缺点:容易欠拟合,分类精度可能不高。
3.朴素贝叶斯算法
from sklearn import naive_bayes
# 先验概率为高斯分布的朴素贝叶斯
model = naive_bayes.GaussianNB()
# 先验概率为多项式分布的朴素贝叶斯
model = naive_bayes.MultinomialNB(alpha=1.0, fit_prior=True, class_prior=None)
# 先验概率为伯努利分布的朴素贝叶斯
model = naive_bayes.BernoulliNB(alpha=1.0, binarize=0.0, fit_prior=True, class_prior=None)
- alpha: 一个浮点数,默认1.0添加拉普拉斯平滑,若为0则不添加。
- binarize: 一个浮点数或者None
- 如果为None,那么会假定原始数据已经二元化了
- 如果是浮点数,那么会以该数值为界,特征取值大于它的作为1;特征取值小于它的作为0。采取这种策略来二元化
- fit_prior: 布尔值。如果为True,则不去学习类别先验概率,替代以均匀分布;如果为False,则去学习类别先验概率
- class_prior: 一个数组。它指定了每个分类的先验概率,如果指定了该参数,则每个分类的先验概率不再从数据集中习得
先验概率为高斯分布时:
先验概率为多项式分布时:
先验概率为伯努利分布时:
- 优点:稳定的分类效率、对小规模的数据表现很好,能处理多分类任务,适合增量式训练,尤其是数据量超出内存时,可以一批批的去增量训练、对缺失数据不太敏感,算法也比较简单,常用于文本分类。
- 缺点:需要知道先验概率,且先验概率很多时候取决于假设,假设的模型可以有很多种,因此在某些时候会由于假设的先验模型的原因导致预测效果不佳;理论上,朴素贝叶斯模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为朴素贝叶斯模型给定输出类别的情况下,假设属性之间相互独立,这个假设在实际应用中往往是不成立的,在属性个数比较多或者属性之间相关性较大时,分类效果不好。而在属性相关性较小时,朴素贝叶斯性能最为良好。对于这一点,有半朴素贝叶斯之类的算法通过考虑部分关联性适度改进。
4.支持向量机SVM
from sklearn.svm import SVC
model = SVC(C=1.0, break_ties=False, cache_size=200, class_weight=None, coef0=0.0, decision_function_shape='ovr', degree=3, kernel='rbf', gamma='auto', max_iter=-1, probability=False, random_state=None, shrinking=True, tol=0.001, verbose=False)
基本概念:
- 分隔超平面:将数据集分割开来的直线叫做分隔超平面。
- 超平面:如果数据集是N维的,那么就需要N-1维的某对象来对数据进行分割。该对象叫做超平面,也就是分类的决策边界。
- 间隔:一个点到分割面的距离,称为点相对于分割面的距离。数据集中所有的点到分割面的最小间隔的2倍,称为分类器或数据集的间隔。
- 最大间隔:SVM分类器是要找最大的数据集间隔。
- 支持向量:坐落在数据边际的两边超平面上的点被称为支持向量
C: float参数 默认值为1.0;该参数为错误项的惩罚系数。C越大,即对分错样本的惩罚程度越大,因此在训练样本中准确率越高,但是泛化能力降低,也就是对测试数据的分类准确率降低。相反,减小C的话,容许训练样本中有一些误分类错误样本,泛化能力强。对于训练样本带有噪声的情况,一般采用后者,把训练样本集中错误分类的样本作为噪声。
kernel: str参数 默认为‘rbf’;该参数代表了算法中采用的核函数类型,可选参数有:‘linear’:线性核函数;‘poly’:多项式核函数;‘rbf’:径像核函数/高斯核;‘sigmod’:sigmod核函数;‘precomputed’:核矩阵,precomputed表示自己提前计算好核函数矩阵,这时候算法内部就不再用核函数去计算核矩阵,而是直接用你给的核矩阵。核矩阵为如下形式:
还有一点需要说明,除了上面限定的核函数外,还可以给出自己定义的核函数,其实内部就是用你自己定义的核函数来计算核矩阵。
degree: int型参数 默认为3;这个参数只对多项式核函数有用,是指多项式核函数的阶数n,如果给的核函数参数是其他核函数,则会自动忽略该参数。
gamma: float参数 默认为auto;核函数系数,只对‘rbf’,‘poly’,‘sigmod’有效。如果gamma为auto,代表其值为样本特征数的倒数,即1/n_features.
coef0: float参数 默认为0.0;核函数中的独立项,只有对‘poly’和‘sigmod’核函数有用,是指其中的参数c
probability: bool参数 默认为False;是否启用概率估计。 这必须在调用fit()之前启用,并且会fit()方法速度变慢。
shrinking: bool参数 默认为True;是否采用启发式收缩方式
tol: float参数 默认为1e^-3;svm停止训练的误差精度
cache_size: float参数 默认为200;指定训练所需要的内存,以MB为单位,默认为200MB。
class_weight: 字典类型或者‘balance’字符串。默认为None;给每个类别分别设置不同的惩罚参数C,如果没有给,则会给所有类别都给C=1,即前面参数指出的参数C.如果给定参数‘balance’,则使用y的值自动调整与输入数据中的类频率成反比的权重。
verbose : bool参数 默认为False;是否启用详细输出。 此设置利用libsvm中的每个进程运行时设置,如果启用,可能无法在多线程上下文中正常工作。一般情况都设为False,不用管它。
max_iter : int参数 默认为-1;最大迭代次数,如果为-1,表示不限制
random_state: int型参数 默认为None;伪随机数发生器的种子,在混洗数据时用于概率估计。
- 优点:使用核函数可以向高维空间进行映射,解决非线性的分类;分类思想很简单,就是将样本与决策面的间隔最大化;分类效果较好
- 缺点:SVM算法对大规模训练样本难以实施,用SVM解决多分类问题存在困难,对缺失数据敏感,对参数和核函数的选择敏感