首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >机器学习14:模型评估与性能提升

机器学习14:模型评估与性能提升

作者头像
用户5473628
发布2019-08-08 15:47:46
9780
发布2019-08-08 15:47:46
举报
文章被收录于专栏:MiningAlgorithmsMiningAlgorithms

模型评估与性能提升

目录:

1,统计学习三要素

1.1,模型

1.2,策略:损失函数与风险函数

1.3,优化算法

2,模型评估

2.1,留出法

2.2,交叉验证法

2.3,自助法

3,网格搜索

4,验证曲线、学习曲线

4.1,验证曲线

4.2,学习曲线

5,模型持久化(model persistence)

6,code:

6.1,网格搜索、模型持久化、类别不平衡(SMOTE、下采样)

6.2,验证曲线、学习曲线、ROC曲线、准确度、精确率、召回率、F1_Score

1,统计学习三要素

1.1,模型:

统计学习方法由三个要素组成:方法 = 模型 + 策略 + 算法。

统计学习首要考虑的问题是学习什么样的模型。在监督学习过程中,模型就是所要学习的条件概率分布或决策函数。 模型的假设空间包含所有可能的条件概率分布或决策函数。例如, 假设决策函数是输入变量的线性函数, 那么模型的假设空间就是所有这些线性函数构成的函数集合,假设空间中的模型一般有无穷多个,即这些线性函数具有不同的参数值,而模型参数的取值同属于一个假设空间。

1.2,策略:损失函数与风险函数:

有了模型的假设空间, 统计学习接着需要考虑的是按照什么样的准则学习或选择最优的模型。统计学习的目标在于从假设空间中选取最优模型,即选择一个最优化的参数向量。

用一个损失函数来度量预测的错误程度,记作L(Y,f(X))。损失函数越小,模型就越好,学习的目标就是选择期望风险最小的模型。

在假设空间、损失函数以及训练数据集确定的情况下,经验风险函数就可以确定。经验风险最小化(empirical riskminimization,ERM)的策略认为,经验风险最小的模型就是最优的模型。根据这一策略,按照经验风险最小化求最优模型就是求解最优化问题:

当样本量很小时,经验风险最小化的效果往往不是很好,会产生过拟合现象。

结构风险最小化(structural risk minimization,SRM)是为了防止过拟合而提出来的策略。结构风险最小化等价于正则化(regularization)。以逻辑回归模型为例,结构化风险最小化就是最小化下面这个损失函数,比上面的式子多了一个正则化项:

1.3,优化算法:

算法是指学习模型的具本计算方法。统计学习基于训练数据,根据模型获取假设空间,然后根据策略从假设这间中选择最优模型,最后需要考虑的是用什么计算方法,求解这个最优模型。

这时,统计学习问题转化为最优化问题,统计学习的算法成为求解最优化问题的算法。

2,模型评估:经验误差与泛化误差

统计学习方法具体使用的损失函数未必是评估时使用的损失函数,当然,两者一致是比较理想的。

一般地,我们把学习器的实际预测输出与样本的真实输出之间的差异成为误差(error)。学习器在训练集上的误差称为训练误差(training error)或经验误差(empiricalerror);在新样本集上的误差称为泛化误差,特别地,在测试数据集上的误差称为测试误差(test error),一般用测试误差作为泛化误差的近似。

训练集S与测试集T的划分方式常见的有一下几种:留出法、交叉验证法、自助法。

2.1,留出法:

假设数据集D,那么留出法的划分方式可以表述为:D = S ∪T,S ∩ T = Ø;

2.2,交叉验证法:

交叉验证法先将数据集D划分为k个大小相似的互斥子集,即D = D1 ∪ D2 ∪ . . . ∪ Dk,Di ∩Dj = Ø(i不等于j),因此,有时也把交叉验证法称为k折交叉验证。交叉验证还产生了很多变种,比如留一法等;

2.3,自助法:

自助法以自主采样法为基础,留出法与交叉验证法都是使用分层采样的方式进行数据采样与划分,而自助法则是使用有放回重复采样的方式进行数据采样,即我们每次从数据集D中取一个样本作为训练集中的元素,然后把该样本放回,重复该行为m次,这样我们就可以得到大小为m的训练集,在这里面有的样本重复出现,有的样本则没有出现过,我们把那些没有出现过的样本作为测试集。样本在m次采样中始终不被采到的概率是(1-(1/m))^m,取极限得到:

把没有出现在采样集(包含m个样本)的样本作为测试集(36.8%的样本),这样的测试结果称为包外估计。

另外在本系列的博文《机器学习5:集成学习--Bagging与随机森林》中也有对自主采样法和包外估计的解释。

自助法产生的数据集改变了初始数据集的分布,这会引入估计偏差,因此,在初始数据量足够时,留出法和交叉验证法更常用一些。

3,网格搜索:

机器学习模型中的一种调参选择。

这里的网格指的是不同参数不同取值交叉后形成的一个多维网格空间。比如参数a可以取1、2,参数b可以取3、4,参数c可以取5、6,那么形成的多维网格空间一共包含2*2*2=8种情况,网格搜索就是遍历这8种情况进行模型训练和验证,最终选择出效果最优的参数组合。

4,验证曲线(validationcurves)、学习曲线:

使用交叉验证的方法可以估计模型的平均性能;通过学习曲线可以判断模型的偏差和方差;通过验证曲线可以判断模型参数对于模型的过拟合和欠拟合。

4.1,验证曲线:

为了验证一个模型,我们需要分数函数,例如,分类器准确率。选择一个估计量的多个超参数的正确方式是网格搜索或类似的方法,这类方法选择在一个或多个验证集上具有最高分数的超参数。注意,如果我们根据一个验证分数优化超参数,那么这个超参数是有偏的,不再是一个好的泛化估计。为了得到一个适当的泛化估计,我们必须在另一个检验集上计算分数。然而,有时候画出一个超参数对训练分数和验证分数的影响,找出估计量是否过度拟合或欠拟合是有帮助的。

4.2,学习曲线:

一个学习曲线显示一个估计量的训练分数和验证分数随着训练样本量的变化情况。学习曲线可以帮助我们找出增加更多训练数据的受益程度,估计量是否遭遇方差/偏差误差。如果训练分数和验证分数收敛到的值,随着训练集样本的增加而变得太小,那么增加训练样本益处不大。

5,模型持久化(modelpersistence):

当数据量比较大的时候,我们将数据放入到模型中训练是一件比较耗时的事情。我们想看训练的结果需要而又不想重新训练的时候,我们可以将训练好的模型持久化到文件中(保存到本地),这样可以随时查看模型训练的结果并使用训练好的模型。

模型部署一般就是把训练的模型持久化,然后运行服务器加载模型,并提供REST或其它形式的服务接口。

6,code:

6.1,网格搜索、模型持久化:

code:1,GridSearchCV:网格搜索;2,模型持久化(模型保存至本地);3,SMOTE:利用合成数据(插值)方法,调整sample数量;4,模型持久化:将经过清洗和特征工程后的数据存入本地,以便后续进一步建模分析;5,经过下采样后的数据训练结果。

from sklearn import svm, datasets
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection  import train_test_split

# 1,GridSearchCV:网格搜索
iris = datasets.load_iris()
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2, random_state=16)

parameters = {'kernel':('linear', 'rbf'), 'C':[1, 10]}
svc = svm.SVC(gamma="scale")
clf = GridSearchCV(svc, parameters, cv=5)   # cv=5:5折交叉验证
clf.fit(x_train, y_train)
print("最优参数列表:", clf.best_params_,';', "score值:",clf.best_score_)
print(sorted(clf.cv_results_.keys()))

# 2,模型持久化(模型保存至本地):
from sklearn.externals import joblib

best_clf_model = clf.best_estimator_
joblib.dump(best_clf_model, "clf.model")
best_clf_model = joblib.load("clf.model") # 加载模型就可以用,无需重新训练
print(best_clf_model.predict(x_test))


# 3,SMOTE:利用合成数据(插值)方法,调整sample数量
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.decomposition import PCA

from imblearn.combine import SMOTETomek

print(__doc__)

X, y = make_classification(n_classes=2, class_sep=2, weights=[0.1, 0.9],  # 生成数据
                           n_informative=3, n_redundant=1, flip_y=0,
                           n_features=20, n_clusters_per_class=1,
                           n_samples=100, random_state=10)

pca = PCA(n_components=2)  # Instanciate a PCA object for the sake of easy visualisation
X_vis = pca.fit_transform(X)   # Fit and transform x to visualise inside a 2D feature space

sm = SMOTETomek()   # Apply SMOTE + Tomek links
X_resampled, y_resampled = sm.fit_sample(X, y)
X_res_vis = pca.transform(X_resampled)

f, (ax1, ax2) = plt.subplots(1, 2)   # Two subplots, unpack the axes array immediately

c0 = ax1.scatter(X_vis[y == 0, 0], X_vis[y == 0, 1], label="Class #0",
                 alpha=0.5)
c1 = ax1.scatter(X_vis[y == 1, 0], X_vis[y == 1, 1], label="Class #1",
                 alpha=0.5)
ax1.set_title('Original set')

ax2.scatter(X_res_vis[y_resampled == 0, 0], X_res_vis[y_resampled == 0, 1],
            label="Class #0", alpha=0.5)
ax2.scatter(X_res_vis[y_resampled == 1, 0], X_res_vis[y_resampled == 1, 1],
            label="Class #1", alpha=0.5)
ax2.set_title('SMOTE + Tomek')

for ax in (ax1, ax2):   # make nice plotting
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.get_xaxis().tick_bottom()
    ax.get_yaxis().tick_left()
    ax.spines['left'].set_position(('outward', 10))
    ax.spines['bottom'].set_position(('outward', 10))
    ax.set_xlim([-6, 8])
    ax.set_ylim([-6, 6])

plt.figlegend((c0, c1), ('Class #0', 'Class #1'), loc='lower center',
              ncol=2, labelspacing=0.)
plt.tight_layout(pad=3)
plt.show()


# 4,模型持久化:将经过清洗和特征工程后的数据存入本地,以便后续进一步建模分析
from collections import Counter

from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import make_pipeline

from imblearn.under_sampling import RandomUnderSampler
from imblearn.pipeline import make_pipeline as make_pipeline_imb
from imblearn.metrics import classification_report_imbalanced
import pickle

print(__doc__)

categories = ['alt.atheism', 'talk.religion.misc',
              'comp.graphics', 'sci.space']
newsgroups_train = fetch_20newsgroups(subset='train',
                                      categories=categories)
newsgroups_test = fetch_20newsgroups(subset='test',
                                     categories=categories)

X_train, y_train, X_test, y_test = newsgroups_train.data, newsgroups_train.target, newsgroups_test.data, newsgroups_test.target

print('Training class distributions summary: {}'.format(Counter(y_train)))
print('Test class distributions summary: {}'.format(Counter(y_test)))


with open('newsgroups_train.pickle','wb') as handle:   # 把数据存在pickle中
    pickle.dump(newsgroups_train,handle)

with open('newsgroups_test.pickle','wb') as handle:
    pickle.dump(newsgroups_test,handle)
    
with open('newsgroups_train.pickle','rb') as handle:   # 读数据
    newsgroups_train = pickle.load(handle)

with open('newsgroups_test.pickle','rb') as handle:
    newsgroups_test = pickle.load(handle)


pipe = make_pipeline(TfidfVectorizer(),    # 原始数据类别不平衡训练结果
                     MultinomialNB())
pipe.fit(X_train, y_train)
y_pred = pipe.predict(X_test)
print(classification_report_imbalanced(y_test, y_pred))


# 5,经过下采样后的数据训练结果:
pipe = make_pipeline_imb(TfidfVectorizer(),
                         RandomUnderSampler(),
                         MultinomialNB())

pipe.fit(X_train, y_train)
y_pred = pipe.predict(X_test)
print(classification_report_imbalanced(y_test, y_pred))

6.2,验证曲线、学习曲线、ROC曲线、准确度、精确率、召回率、F1_Score:

code:1, 建立随机森林模型;2,验证曲线;3,学习曲线;4,ROC曲线;5,计算准确度、精确率、召回率、F1_Score(综合评价指标)

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import validation_curve,learning_curve

from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score,roc_curve

from sklearn.metrics import f1_score
from sklearn.metrics import accuracy_score
from sklearn.metrics import precision_score, recall_score
%matplotlib inline

# 1,建立随机森林模型:
iris_data = load_iris()
features = iris_data.data
labels = iris_data.target
 
RF = RandomForestClassifier(max_depth = 8, random_state = 0)
params_grid = np.linspace(25,200,8).astype(int)

# 2,验证曲线:
train_scores,validation_scores = validation_curve(RF,features,labels,'n_estimators',params_grid,cv=5)  #其他参数不变,观察评估器数量对训练得分的影响
print('######Validation Curve')
print('train_score\n',train_scores, 'validation_score\n',validation_scores)

plt.figure()   #可视化生成训练、验证曲线
plt.plot(params_grid, np.average(train_scores,axis = 1),color = 'red')
plt.plot(params_grid,np.average(validation_scores,axis = 1),color = 'black')
plt.title('Training curve')
plt.xlabel('number of estimator')
plt.ylabel('accuracy')
plt.show()  #同样的方法可以验证其他变量对训练的影响,多次操作,进行参数调整

# 3,学习曲线:
print(len(features))
size_grid = np.array([0.2,0.5,0.7,1])
train_size,train_scores,validation_scores = learning_curve(RF,features,labels,train_sizes = size_grid, cv = 5)
print('######Learning Curve')
print('train_score\n',train_scores, 'validation_score\n',validation_scores)

plt.figure()  # 学习曲线可视化
plt.plot(size_grid,np.average(train_scores, axis = 1), color = 'red')
plt.plot(size_grid, np.average(validation_scores, axis = 1), color = 'black')
plt.title('Learning Curve')
plt.xlabel('sample size')
plt.ylabel('accuracy')
plt.show()

# 4,ROC曲线:
X,y = make_classification(n_samples=10000,n_features=10,n_classes=2,n_informative=5)
X_train,X_test, y_train,y_test = train_test_split(X,y, test_size=0.2,random_state=0)

clf = LogisticRegression()
clf.fit(X_train,y_train)

preds = clf.predict_proba(X_test)[:,1]
fpr,tpr,_=roc_curve(y_test,preds)

df = pd.DataFrame(dict(fpr=fpr,tpr=tpr))

roc_auc= roc_auc_score(y_test,preds)

plt.figure(figsize=[9,8])  # 画图
lw = 2
plt.plot(fpr, tpr, color='orange',
         lw=lw, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic Line')
plt.legend(loc="lower right")
plt.show()

# 5,计算准确度、精确率、召回率、F1_Score:
y_true =  [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0]
y_pred =  [0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,1,1,1,0,0]

accu=accuracy_score(y_true,y_pred)        # 准确度
prec = precision_score(y_true,y_pred)     # 精确率
reca = recall_score(y_true,y_pred)        # 召回率
F1_score = f1_score(y_true,y_pred)        # 综合评价指标:F1_Score
print('accuracy = %f, precision = %f, recall = %f, F1_score = %f '% (accu, prec, reca, F1_score))

Reference:

《西瓜书》

《统计学习方法》

https://scikit-learn.org/stable/modules/model_persistence.html

https://www.jianshu.com/p/ad2bfc08b9e2

https://blog.csdn.net/michael_yt/article/details/74737489

https://blog.csdn.net/sinat_29957455/article/details/79686990

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 MiningAlgorithms 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档