以前的数据都是通过了规范化处理,并且模型也大多数采用了默认的初始化配置ios
可是在世纪研究和工做种接触到的数据都是这样规整的吗?难道默认配置就最佳的吗?数组
3.1模型实用技巧数据结构
一旦咱们肯定使用某个模型 本书所提供的程序库就能够帮助咱们从标准的训练数据种,依靠默认的配置学习到模型所须要的参数;app
接下来,咱们即可以利用这组得来的参数指导模型在测试数据上进行预测,进而对模型的表现进行评价dom
可是这套方案不能保证:机器学习
①全部用于训练的数据特征都是最好的函数
②学习获得的参数必定是最优的性能
③默认配置下的模型老是最佳的学习
Together 咱们能够从多个角度对在前面使用过的模型进行性能提高 (预处理数据 控制参数 优化模型配置)测试
特征提高(特征抽取和特征筛选)
特征抽取
所谓特征抽取 就是逐条将原始数据转化维特征向量的形式 这个过程同时涉及对数据特征的量化表示
原始数据 :
1数字化的信号数据(声纹,图像)
2还有大量符号化的文本
①咱们没法直接将符号化的文字自己用于计算任务 而是须要经过某些处理手段 ,预先将文本量化为特征向量
有些用符号表示的数据特征已经相对结构化,而且以字典这种数据结构进行存储。
这时咱们使用DictVectorizer 对特征进行抽取和向量化
measurements=[{'city':'Dubai','temperature':33.},{'city':'London','temperature':12.}, {'city':'San Fransisco','temperature':18.}] from sklearn.feature_extraction import DictVectorizer vec=DictVectorizer() #初始化DictVectorizer()特征抽取器 print(vec.fit_transform(measurements).toarray()) #输出转化后的特征矩阵 print(vec.get_feature_names()) #输出各个维度特征含义 #DictVectorizer()特征抽取器对类别型特征进行了one-hot处理,对数值型特征没作进一步处理
DiceVectorizer 对特征的处理方式(字典):
1类别行 使用0/1二值方式
2数字型 维持原始数值便可
②另一些文本数据更为原始 知识一系列的字符串 咱们采用词袋法对特征进行抽取和向量化
词袋法的两种计算方式
CountVectorizer
TfidVectorizer
(a.)CountVectorizer——每一个词(Term)在该训练文本中出现的频率(Term Frequency);
(b.)TfidfVectorizer——除了考量某一词汇在当前文本中出现的频率(Term Frequency)外,还要关注包含这个词汇的文本条数的倒数(Inverse Document Frequency)。训练文本的条目越多,TfidfVectorizer这种特征量化的方式就更有优点,由于计算词频(Term Frequency)的目的在于找出对所在文本的含义更有贡献的重要词汇
若是一个词几乎在每篇文章中都出现,说明这个词是经常使用词,不会帮助模型对文本进行分类。此外,在每条文本中都出现的经常使用词汇成为停用词(Stop Words),停用词在文本特征抽取时须要过滤掉。
#使用CountVectorizer 而且在不去掉停用词的条件下,对文本进行量化的朴素贝叶斯分类性能预测 from sklearn.datasets import fetch_20newsgroups#20类新闻文本 from sklearn.model_selection import train_test_split from sklearn.feature_extraction.text import CountVectorizer from sklearn.naive_bayes import MultinomialNB from sklearn.metrics import classification_report news=fetch_20newsgroups(subset='all') X_train,X_test,y_train,y_test=train_test_split(news.data,news.target,test_size=0.25,random_state=33) count_vec=CountVectorizer() #默认形式初始化词频统计器(不去停用词) X_count_train=count_vec.fit_transform(X_train) X_count_test=count_vec.transform(X_test) mnb_count=MultinomialNB() mnb_count.fit(X_count_train,y_train) #用朴素贝叶斯分类器对词频统计器(不去停用词)处理后的样本进行参数学习 print('The accuracy of classifying 20newsgroups using Naive Bayes(CountVectorizer without filtering stopwords):', mnb_count.score(X_count_test,y_test)) y_count_predict=mnb_count.predict(X_count_test) print(classification_report(y_test,y_count_predict,target_names=news.target_names))
#使用TfidVectorizer 而且在不去掉停用词的条件下,对文本进行量化的朴素贝叶斯分类性能预测 from sklearn.datasets import fetch_20newsgroups from sklearn.model_selection import train_test_split from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.naive_bayes import MultinomialNB from sklearn.metrics import classification_report news=fetch_20newsgroups(subset='all') X_train,X_test,y_train,y_test=train_test_split(news.data,news.target,test_size=0.25,random_state=33) tfidf_vec=TfidfVectorizer() #默认形式初始化tfidf统计器(不去停用词) X_tfidf_train=tfidf_vec.fit_transform(X_train) X_tfidf_test=tfidf_vec.transform(X_test) mnb_tfidf=MultinomialNB() mnb_tfidf.fit(X_tfidf_train,y_train) #用朴素贝叶斯分类器对tfidf统计器(不去停用词)处理后的样本进行参数学习 print('The accuracy of classifying 20news with Naive Bayes(TfidfVectorizer without filtering stopwords):', mnb_tfidf.score(X_tfidf_test,y_test)) y_tfidf_predict=mnb_tfidf.predict(X_tfidf_test) print(classification_report(y_test,y_tfidf_predict,target_names=news.target_names)) #在训练文本量较多的时候,利用TfidfVectorizer压制一些经常使用词汇对分类决策的干扰
#分别使用CountVectorizer与TfidVectorizer 而且在去掉停用词的条件下,对文本进行量化的朴素贝叶斯分类性能预测 from sklearn.datasets import fetch_20newsgroups from sklearn.model_selection import train_test_split from sklearn.feature_extraction.text import CountVectorizer from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.naive_bayes import MultinomialNB news=fetch_20newsgroups(subset='all') X_train,X_test,y_train,y_test=train_test_split(news.data,news.target,test_size=0.25,random_state=33) count_filter_vec=CountVectorizer(analyzer='word',stop_words='english') #初始化词频统计器(去停用词) X_count_filter_train=count_filter_vec.fit_transform(X_train) X_count_filter_test=count_filter_vec.transform(X_test) mnb_count_filter=MultinomialNB() mnb_count_filter.fit(X_count_filter_train,y_train) print('The accuarcy of classifying 20newsgroups using Naive Bayes(CountVetorizer by filtering stopwords):', mnb_count_filter.score(X_count_filter_test,y_test)) y_count_filter_predict=mnb_count_filter.predict(X_count_filter_test) from sklearn.metrics import classification_report print(classification_report(y_test,y_count_filter_predict,target_names=news.target_names)) tfidf_filter_vec=TfidfVectorizer(analyzer='word',stop_words='english') #初始化tfidf统计器(去停用词) X_tfidf_filter_train=tfidf_filter_vec.fit_transform(X_train) X_tfidf_filter_test=tfidf_filter_vec.transform(X_test) mnb_tfidf_filter=MultinomialNB() mnb_tfidf_filter.fit(X_tfidf_filter_train,y_train) print('The accuracy of classifying 20newsgroups with Naive Bayes(TfidfVectorizer by filtering stopwords):', mnb_tfidf_filter.score(X_tfidf_filter_test,y_test)) y_tfidf_filter_predict=mnb_tfidf_filter.predict(X_tfidf_filter_test) print(classification_report(y_test,y_tfidf_filter_predict,target_names=news.target_names))
特征筛选
良好的数据特征组合不须要太多,即可以使模型的性能表现突出。
冗余的特征不会影响到模型的性能,不过却使得CPU的计算作了无用功
主成分分析主要用于去除多余的那些线性相关的特长组合,缘由在于这些冗余的特征组合并不会对模型训练有更多贡献。而不良的特征天然会下降模型的精度。
特征筛选与PCA 这类经过选择主成分进行对特征进行重建的方法略有区别:对于PCA而言,咱们常常没法解释重建以后的特征;
可是特征筛选不存在对特征值的修改 而更加侧重于寻找那些对模型的性能提高较大的少许特征。
#使用Titanic数据集,经过特征筛选的方法一步步提高决策树的预测性能 import pandas as pd titanic=pd.read_csv('http://biostat.mc.vanderbilt.edu/wiki/pub/Main/DataSets/titanic.txt') y=titanic['survived'] #分离特征与标签 X=titanic.drop(['row.names','name','survived'],axis=1) X['age'].fillna(X['age'].mean(),inplace=True) #填充缺失值 X.fillna('UNKNOWN',inplace=True) from sklearn.cross_validation import train_test_split X_train,X_test,y_train,y_test = train_test_split(X, y, test_size=0.25, random_state=33) from sklearn.feature_extraction import DictVectorizer vec=DictVectorizer() X_train=vec.fit_transform(X_train.to_dict(orient='record')) #类别型特征向量化one-hot X_test=vec.transform(X_test.to_dict(orient='record')) print(len(vec.feature_names_)) #使用决策树模型对全部特征进行预测并评估 from sklearn.tree import DecisionTreeClassifier dt=DecisionTreeClassifier(criterion='entropy') dt.fit(X_train,y_train) dt.score(X_test,y_test) from sklearn import feature_selection fs=feature_selection.SelectPercentile(feature_selection.chi2,percentile=20) #筛选前20%特征建模 X_train_fs=fs.fit_transform(X_train,y_train) dt.fit(X_train_fs,y_train) X_test_fs=fs.transform(X_test) dt.score(X_test_fs,y_test) from sklearn.cross_validation import cross_val_score import numpy as np percentiles=range(1,100,2) results=[] for i in percentiles: fs=feature_selection.SelectPercentile(feature_selection.chi2,percentile=i) X_train_fs=fs.fit_transform(X_train,y_train) scores=cross_val_score(dt,X_train_fs,y_train,cv=5) #经过交叉验证,按固定间隔2%的步长筛选特征 results=np.append(results,scores.mean()) print(results) opt=np.where(results==results.max())[0] print('Optimal number of features %d' % percentiles[opt[0]]) import pylab as pl pl.plot(percentiles,results) pl.xlabel('percentiles of features') pl.ylabel('accuracy') pl.show() from sklearn import feature_selection fs=feature_selection.SelectPercentile(feature_selection.chi2,percentile=7) #使用最佳筛选后的特征进行相同建模 X_train_fs=fs.fit_transform(X_train,y_train) dt.fit(X_train_fs,y_train) X_test_fs=fs.transform(X_test) dt.score(X_test_fs,y_test)
模型正则化
欠拟合与过拟合
模型的泛化能力:模型对未知数据的预测能力
拟合:机器学习模型在训练的过程当中,经过更新参数,使模型不断契合可观测数据(训练集)的过程
存在过拟合和欠拟合两种模型的状态
#使用线性回归模型在披萨训练样本上进行拟合 X_train=[[6],[8],[10],[14],[18]] y_train=[[7],[9],[13],[17.5],[18]] from sklearn.linear_model import LinearRegression regressor=LinearRegression() #默认配置初始化线性回归模型 regressor.fit(X_train,y_train) #根据训练集数据建模 import numpy as np xx=np.linspace(0,26,100) #构建测试集 xx=xx.reshape(xx.shape[0],1) yy=regressor.predict(xx) import matplotlib.pyplot as plt plt.scatter(X_train,y_train) plt1,=plt.plot(xx,yy,label='Degree=1') plt.axis([0,25,0,25]) plt.xlabel('independent variable') plt.ylabel('dependent variable') plt.legend(handles=[plt1]) plt.show() print('The R-squared value of Linear Regressor performing on the training data is', regressor.score(X_train,y_train))
#使用二次多项式回归模型在披萨训练样本上进行拟合 X_train=[[6],[8],[10],[14],[18]] y_train=[[7],[9],[13],[17.5],[18]] from sklearn.preprocessing import PolynomialFeatures poly2=PolynomialFeatures(degree=2) #多项式特征产生器 X_train_poly2=poly2.fit_transform(X_train) #X_train_poly2即为由训练集构造出的二次多项式特征 from sklearn.linear_model import LinearRegression regressor_poly2=LinearRegression() regressor_poly2.fit(X_train_poly2,y_train) #建模生产的二次多项式回归模型 import numpy as np xx=np.linspace(0,26,100) xx=xx.reshape(xx.shape[0],1) xx_poly2=poly2.transform(xx) #对测试集数据构造二次多项式特征 yy_poly2=regressor_poly2.predict(xx_poly2) import matplotlib.pyplot as plt plt.scatter(X_train,y_train) plt2,=plt.plot(xx,yy_poly2,label='Degree=2') plt.axis([0,25,0,25]) plt.xlabel('independent variable') plt.ylabel('dependent variable') plt.legend(handles=[plt2]) plt.show() print('The R-squared value of Polynomial Regressor(Degree=2) performing on the training data is', regressor_poly2.score(X_train_poly2,y_train))
#使用4次多项式回归模型在披萨训练样本上进行拟合 X_train=[[6],[8],[10],[14],[18]] y_train=[[7],[9],[13],[17.5],[18]] from sklearn.preprocessing import PolynomialFeatures poly4=PolynomialFeatures(degree=4) #多项式特征产生器 X_train_poly4=poly4.fit_transform(X_train) #X_train_poly2即为由训练集构造出的二次多项式特征 from sklearn.linear_model import LinearRegression regressor_poly4=LinearRegression() regressor_poly4.fit(X_train_poly4,y_train) #建模生产的二次多项式回归模型 import numpy as np xx=np.linspace(0,26,100) xx=xx.reshape(xx.shape[0],1) xx_poly2=poly4.transform(xx) #对测试集数据构造二次多项式特征 yy_poly2=regressor_poly4.predict(xx_poly2) import matplotlib.pyplot as plt plt.scatter(X_train,y_train) plt2,=plt.plot(xx,yy_poly2,label='Degree=2') plt.axis([0,25,0,25]) plt.xlabel('independent variable') plt.ylabel('dependent variable') plt.legend(handles=[plt2]) plt.show() print('The R-squared value of Polynomial Regressor(Degree=2) performing on the training data is', regressor_poly4.score(X_train_poly4,y_train))
#评估3种回归模型在测试数据集上的性能表现 X_test=[[6],[8],[11],[16]] y_test=[[8],[12],[15],[18]] print('Linear regression:',regressor.score(X_test,y_test)) X_test_poly2=poly2.transform(X_test) print('Polynomial 2 regression:',regressor_poly2.score(X_test_poly2,y_test)) X_test_poly4=poly4.transform(X_test) print('Polynomial 4 regression:',regressor_poly4.score(X_test_poly4,y_test))
Together
当模型复杂度很低 模型不只没有对训练集上的数据有良好的拟合状态,并且在测试集上也表现平平,这种状况叫欠拟合,如线性回归预测
可是,当咱们意味追求很高的模型复杂度,尽管模型几乎彻底拟合了所有训练数据 但模型也变得很是波动 几乎丧失了对未知数据的预测能力 ,这种状况叫过拟合,如四次多项式回归预测。
避免欠拟合 在要求增长模型复杂度 提升在可观测数据上的表现的同时 又须要兼顾模型的泛化力 防止发生过拟合。
正则化方法(L1正则化和L2正则化)
正则化的目的在于提升模型在未知测试数据上的泛化力,避免参数过拟合
所以,正则化的常见方法都是在原模型优化目标的基础上,增长对参数的惩罚项
L1正则化是让参数向量中的许多元素趋向于0,让有效特征变得稀疏,对应的L1正则化模型称为Lasso。
L2正则化是让参数向量中的大部分元素都变得很小,压制了参数之间的差别性,对应的L2正则化模型称为Ridge
#Lasso模型在4次多项式特征上拟合的拟合 from sklearn.linear_model import Lasso lasso_poly4=Lasso() #默认配置初始化Lasso lasso_poly4.fit(X_train_poly4,y_train) #利用Lasso对四次多项式特征回归拟合 print(lasso_poly4.score(X_test_poly4,y_test)) #在测试集上进行评估 print(lasso_poly4.coef_) #输出Lasso模型的参数列表 print(' ') print(regressor_poly4.score(X_test_poly4,y_test)) #对比看一下不加正则化项的四次多项式回归拟合 print(regressor_poly4.coef_) #Ridge模型在4次多项式特征上的拟合表现 from sklearn.linear_model import Ridge ridge_poly4=Ridge() #默认配置初始化Ridge ridge_poly4.fit(X_train_poly4,y_train) #利用Ridge对四次多项式特征回归拟合 print(ridge_poly4.score(X_test_poly4,y_test)) #在测试集上进行评估 print(ridge_poly4.coef_) #输出Ridge模型的参数列表 print(np.sum(ridge_poly4.coef_**2)) print(' ') print(regressor_poly4.coef_) #对比看一下不加正则化项的四次多项式回归拟合 print(np.sum(regressor_poly4.coef_**2))
模型检验
在实际生活种(比赛)咱们不知道 模型对测试集预测的答案 (当咱们书中没有测试集数据的状况下)
咱们把现有的数据进行采样分割 成 训练集和开发集(验证集)
模型校验方式 留一验证 交叉验证
留一验证(用于早期)
随机采样必定比例做为训练集 ,留下的做为验证集 一般比例为7 3 可是因为对于验证集合随机采样的不肯定性 使模型的性能不稳定
交叉验证(留一验证的高级版本)
屡次进行留一验证 后求得平均结果
超参数搜索
多数状况先,超参数的选择是无限的。所以在有限的时间内,除了能够验证预设几种超参数组合之外,也能够经过启发式的搜索方式对超参数组合进行调优(网格搜索),同时因为超参数的验证过程之间彼此独立,所以为并行计算提供了可能(并行搜索)。
网格搜索
对多种超参数组合的空间进行暴力搜索。每一套超参数组合被带入到学习函数中做为新的模型,而且为了比较新模型之间的性能,每一个模型都会采用交叉验证的方法在多组相同的训练集和开发数据集下进行评估
#使用单线程对文本分类的朴素贝叶斯模型的超参数组合执行网格搜索 from sklearn.datasets import fetch_20newsgroups import numpy as np from sklearn.model_selection import train_test_split from sklearn.svm import SVC from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.pipeline import Pipeline from sklearn.model_selection import GridSearchCV news=fetch_20newsgroups(subset='all') #选取前3000条数据 X_train,X_test,y_train,y_test=train_test_split(news.data[:3000],news.target[:3000],test_size=0.25,random_state=33) #使用Pipline 简化系统搭建流程 将文本抽取与分类器模型串联起来 clf=Pipeline([('vect',TfidfVectorizer(stop_words='english',analyzer='word')),('svc',SVC())]) #超参数svc_gamma有4个 svc_C有3个 超参数组合一共有12种 使用np.logspace函数来选取超参数 parameters = {'svc__gamma': np.logspace(-2, 1, 4), 'svc__C': np.logspace(-1, 1, 3)} gs=GridSearchCV(clf,parameters,verbose=2,refit=True,cv=3) gs.fit(X_train,y_train) gs.best_params_,gs.best_score_ print(gs.score(X_test,y_test))
关于网格搜索的参数:
GridSearchCV(estimator,param_grid, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True,cv=None, verbose=0,
pre_dispatch='2*n_jobs', error_score='raise',return_train_score=True)
estimator:所使用的分类器。
param_grid:值为字典或者列表,即须要最优化的参数的取值。
scoring :准确度评价标准,默认None。
cv :交叉验证参数,默认None,使用三折交叉验证(cv=3)。
refit :默认为True,程序将会以交叉验证训练集获得的最佳参数,从新对全部可用的训练集与开发集进行,做为最终用于性能评估的最佳模型参数。即在搜索参数结束后,用最佳参数结果再次fit一遍所有数据集
verbose:日志冗长度,int:冗长度,0:不输出训练过程,1:偶尔输出,>1:对每一个子模型都输出。
n_jobs: 并行数,int:个数,-1:跟CPU核数一致, 1:默认值。
pre_dispatch:指定总共分发的并行任务数。当n_jobs大于1时,数据将在每一个运行点进行复制,这可能致使OOM,
而设置pre_dispatch参数,则能够预先划分总共的job数量,使数据最多被复制pre_dispatch次
并行搜索
n_jobs=-1是用cpu全部的核训练 即并行的方式
#使用多个线程对文本分类的朴素贝叶斯模型的超参数组合执行并行化的网格搜索 from sklearn.datasets import fetch_20newsgroups import numpy as np from sklearn.model_selection import train_test_split from sklearn.svm import SVC from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.pipeline import Pipeline from sklearn.model_selection import GridSearchCV news=fetch_20newsgroups(subset='all') #选取前3000条数据 X_train,X_test,y_train,y_test=train_test_split(news.data[:3000],news.target[:3000],test_size=0.25,random_state=33) #使用Pipline 简化系统搭建流程 将文本抽取与分类器模型串联起来 clf=Pipeline([('vect',TfidfVectorizer(stop_words='english',analyzer='word')),('svc',SVC())]) #超参数svc_gamma有4个 svc_C有3个 超参数组合一共有12种 使用np.logspace函数来选取超参数 parameters = {'svc__gamma': np.logspace(-2, 1, 4), 'svc__C': np.logspace(-1, 1, 3)} #初始化配置并行网格搜索 n_jobs=-1表明使用该计算机的所有CPU gs=GridSearchCV(clf,parameters,verbose=2,refit=True,cv=3,n_jobs=-1) gs.fit(X_train,y_train) gs.best_params_,gs.best_score_ print(gs.score(X_test,y_test))