绍兴网站制作推广,wordpress无法选择服务器配置,免费注册网页的网站,中山古镇做网站的公司文章目录1. 数据预览2. 数据集拆分3. 二分类4. 性能评估4.1 交叉验证4.2 准确率、召回率4.3 受试者工作特征#xff08;ROC#xff09;曲线5. 多分类6. 误差分析6.1 检查混淆矩阵本文为《机器学习实战#xff1a;基于Scikit-Learn和TensorFlow》的读书笔记。 中文翻译参考
…
文章目录1. 数据预览2. 数据集拆分3. 二分类4. 性能评估4.1 交叉验证4.2 准确率、召回率4.3 受试者工作特征ROC曲线5. 多分类6. 误差分析6.1 检查混淆矩阵本文为《机器学习实战基于Scikit-Learn和TensorFlow》的读书笔记。 中文翻译参考
数据集为70000张手写数字图片MNIST 数据集下载
1. 数据预览
导入数据
from scipy.io import loadmat
data loadmat(mnist-original.mat)
data{__header__: bMATLAB 5.0 MAT-file Platform: posix, Created on: Sun Mar 30 03:19:02 2014,__version__: 1.0,__globals__: [],mldata_descr_ordering: array([[array([label], dtypeU5), array([data], dtypeU4)]],dtypeobject),data: array([[0, 0, 0, ..., 0, 0, 0],[0, 0, 0, ..., 0, 0, 0],[0, 0, 0, ..., 0, 0, 0],...,[0, 0, 0, ..., 0, 0, 0],[0, 0, 0, ..., 0, 0, 0],[0, 0, 0, ..., 0, 0, 0]], dtypeuint8),label: array([[0., 0., 0., ..., 9., 9., 9.]])}数据是一个字典它的 keys
data.keys()dict_keys([__header__, __version__, __globals__, mldata_descr_ordering, data, label])label 标签是啥数字图片的数是多少
y data[label].ravel()
# y.shape
yarray([0., 0., 0., ..., 9., 9., 9.])数据是啥70000行784列28*28的图片
data[data]array([[0, 0, 0, ..., 0, 0, 0],[0, 0, 0, ..., 0, 0, 0],[0, 0, 0, ..., 0, 0, 0],...,[0, 0, 0, ..., 0, 0, 0],[0, 0, 0, ..., 0, 0, 0],[0, 0, 0, ..., 0, 0, 0]], dtypeuint8)import pandas as pd
X pd.DataFrame(data[data].T)
X
# print(X.shape)选一个数据看看
%matplotlib inline
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
some_digit np.array(X.iloc[36000,])
some_digit_img some_digit.reshape(28,28)
plt.imshow(some_digit_img, interpolationnearest)
# plt.axis(off)
plt.show()看起来像是5y[36000]输出5.0确实是5
2. 数据集拆分
MNIST 数据集已经事先被分成了一个训练集前 60000 张图片和一个测试集最后 10000 张图片
X_train, x_test, y_train, y_test X[:60000], X[60000:], y[:60000], y[60000:]数据集是顺序的1-9我们打乱数据
避免交叉验证的某一折里没有某个数字有些算法对训练样本的顺序是敏感的避免
import numpy as np
shuffle_idx np.random.permutation(60000)
X_train, y_train X_train.iloc[shuffle_idx], y_train[shuffle_idx]
X_train3. 二分类
选择随机梯度下降模型、训练一个二分类器预测是不是数字5
y_train_5 (y_train 5)
y_test_5 (y_test 5)
from sklearn.linear_model import SGDClassifier
sgd_clf SGDClassifier(random_state1)
sgd_clf.fit(X_train, y_train_5)sgd_clf.predict([some_digit])
array([ True]) # 预测上面那张图片是5答对了4. 性能评估
4.1 交叉验证
手写版
from sklearn.model_selection import StratifiedKFold
from sklearn.base import clone# 分层采样前一章介绍过分成3份
skfolds StratifiedKFold(n_splits3)
for train_index, test_index in skfolds.split(X_train, y_train_5):# 采用上面的模型的clone版本clone_clf clone(sgd_clf)X_train_folds X_train.iloc[train_index]y_train_folds (y_train_5[train_index])X_test_fold X_train.iloc[test_index]y_test_fold (y_train_5[test_index])clone_clf.fit(X_train_folds, y_train_folds)y_pred clone_clf.predict(X_test_fold)n_correct sum(y_pred y_test_fold)print(n_correct / len(y_pred))0.9464
0.9472
0.9659sklearn 内置版
from sklearn.model_selection import cross_val_score
cross_val_score(sgd_clf, X_train, y_train_5, cv3, scoringaccuracy)
# array([0.9464, 0.9472, 0.9659])写一个预测不是5的分类器直接返回 全部不是5
from sklearn.base import BaseEstimator
class not5(BaseEstimator):def fit(self,X,yNone):passdef predict(self,X):return np.zeros((len(X),1),dtypebool) # 返回全部不是5
not5_clf not5()
cross_val_score(not5_clf,X_train,y_train_5,cv3,scoringaccuracy)
# array([0.91015, 0.90745, 0.91135])因为只有 10% 的图片是数字 5总是猜测某张图片不是 5也有90%的可能性是对的。 这证明了为什么精度通常来说 不是一个好的性能度量指标特别是当你处理有偏差的数据集比方说其中一些类比其他类频繁得多 4.2 准确率、召回率
精度不是一个好的性能指标混淆矩阵准确率、召回率
# 混淆矩阵
from sklearn.model_selection import cross_val_predict
y_train_pred cross_val_predict(sgd_clf, X_train, y_train_5, cv3)from sklearn.metrics import confusion_matrix
confusion_matrix(y_train_5, y_train_pred)# output
array([[52625, 1954],[ 856, 4565]], dtypeint64)准确率、召回率、F1值(前两者的平均)
F121precision1recall2∗precison ∗recallprecison recallTPTPFNFP2F 1\frac{2}{\frac{1}{\text {precision}}\frac{1}{\text {recall}}}2 * \frac{\text {precison } * \text {recall}}{\text {precison }\text {recall}}\frac{T P}{T P\frac{F NF P}{2}}F1precision1recall122∗precison recallprecison ∗recallTP2FNFPTP
from sklearn.metrics import precision_score, recall_score
precision_score(y_train_5, y_train_pred) # 0.7002607761926676
recall_score(y_train_5, y_train_pred) # 0.8420955543257701from sklearn.metrics import f1_score
f1_score(y_train_5, y_train_pred) # 0.7646566164154103选择标准看需求而定
儿童阅读希望过滤不适合的我们希望高的准确率标记成适合的里面真的适合的比例要很高极大限度保护儿童视频警报预测则希望高的召回率是危险的不能报不危险F1值则要求两者都要比较高
准确率与召回率的折衷
提高决策阈值可以提高准确率降低召回率降低决策阈值可以提高召回率降低准确率 y_scores cross_val_predict(sgd_clf,X_train,y_train_5,cv3,methoddecision_function)
from sklearn.metrics import precision_recall_curve
# help(precision_recall_curve)
precisions, recalls, thresholds precision_recall_curve(y_train_5, y_scores)def plot_precision_recall_vs_threshold(precisions, recalls, thresholds):plt.plot(thresholds, precisions[:-1], b--, labelPrecision)plt.plot(thresholds, recalls[:-1], g-, labelRecall)plt.xlabel(Threshold)plt.legend(locbest)plt.ylim([0, 1])
plot_precision_recall_vs_threshold(precisions, recalls, thresholds)
plt.show()直接画出 准确率与召回率的关系
def plot_precision_recall(precisions, recalls):plt.plot(recalls[:-1], precisions[:-1], b--, labelRecalls VS Precisions)plt.xlabel(Recalls)plt.ylabel(Precisions)plt.legend(locbest)plt.ylim([0, 1])
plot_precision_recall(precisions, recalls)
plt.show()找到准确率 90%的点其召回率为 52%
threshold_90_precision thresholds[np.argmax(precisions 0.9)]
y_train_pred_90 (y_scores threshold_90_precision)
precision_score(y_train_5, y_train_pred_90) # 0.9000318369945877
recall_score(y_train_5, y_train_pred_90) # 0.52149049990776614.3 受试者工作特征ROC曲线
ROC 曲线是真正例率true positive rate召回率对假正例率false positive rate, FPR 反例被错误分成正例的比率的曲线
from sklearn.metrics import roc_curve
# help(roc_curve)
fpr, tpr, thresholds roc_curve(y_train_5, y_scores)def plot_roc_curve(fpr, tpr, labelNone):plt.plot(fpr, tpr, linewidth2, labellabel)plt.plot([0, 1], [0, 1], k--)plt.axis([0, 1, 0, 1])plt.xlabel(False Positive Rate)plt.ylabel(True Positive Rate)
plot_roc_curve(fpr, tpr)
plt.show()比较分类器优劣的方法是测量ROC曲线下的面积AUC面积越接近1越好
完美的分类器的 ROC AUC 等于 1纯随机分类器的 ROC AUC 等于 0.5
from sklearn.metrics import roc_auc_score
roc_auc_score(y_train_5, y_scores) # 0.9603458830084456随机森林 模型对比
from sklearn.ensemble import RandomForestClassifier
forest_clf RandomForestClassifier(random_state42)
y_probas_forest cross_val_predict(forest_clf, X_train, y_train_5, cv3,methodpredict_proba)
help(RandomForestClassifier.predict_proba)
# Returns
# -------
# p : array of shape (n_samples, n_classes), or a list of n_outputs
# such arrays if n_outputs 1.
# The class probabilities of the input samples. The order of the
# classes corresponds to that in the attribute :term:classes_.y_scores_forest y_probas_forest[:, 1] # score proba of positive class
fpr_forest, tpr_forest, thresholds_forest roc_curve(y_train_5,y_scores_forest)
plt.plot(fpr, tpr, b:, labelSGD)
plot_roc_curve(fpr_forest, tpr_forest, Random Forest)
plt.legend(locbest)
plt.show()roc_auc_score(y_train_5, y_scores_forest) # 0.99825770374487235. 多分类
一些算法比如随机森林朴素贝叶斯可以直接处理多类分类问题 其他一些算法比如 SVM 或 线性分类器则是严格的二分类器
但是可以可以把二分类用于多分类当中
上面的数字预测 一个方法是训练10个二分类器是n吗不是n吗n0-9。一个样本进行10次分类选出决策分数最高。这叫做“一对所有”OvA策略也被叫做“一对其他”OneVsRest 另一个策略是对每2个数字都训练一个二分类器一个分类器用来处理数字 0 和数字 1一个用来处理数字 0 和数字 2一个用来处理数字 1 和 2以此类推。 这叫做“一对一”OvO策略。如果有 N 个类。你需要训练N*(N-1)/2个分类器。选出胜出的分类器
OvO主要优点是每个分类器只需要在训练集的部分数据上面进行训练。这部分数据是它所需要区分的那两个类对应的数据
对于大部分的二分类器来说OvA 是更好的选择
sgd_clf.fit(X_train, y_train)
sgd_clf.predict([some_digit]) # array([5.])随机梯度下降分类器探测到是多分类训练了10个分类器分别作出决策
some_digit_scores sgd_clf.decision_function([some_digit])
some_digit_scoresarray([[ -3868.24582957, -27686.91834291, -11576.99227803,-1167.01579458, -21161.58664081, 1445.95448704,-20347.02376541, -11273.60667573, -19012.16864028,-12849.63656789]])np.argmax(some_digit_scores) # 5
sgd_clf.classes_ # array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
sgd_clf.classes_[5] # 5.0label 5 获得的决策值最大所以预测为 5
强制 Scikit-Learn 使用 OvO 策略或者 OvA 策略你可以使用OneVsOneClassifier类或者OneVsRestClassifier类。传递一个二分类器给它的构造函数
from sklearn.multiclass import OneVsOneClassifier
ovo_clf OneVsOneClassifier(SGDClassifier(random_state1))
ovo_clf.fit(X_train, y_train)
ovo_clf.predict([some_digit]) # array([5.])len(ovo_clf.estimators_) # 45组合数 C-n-2对于随机森林模型不必使用上面的策略它可以进行多分类
forest_clf.fit(X_train, y_train)
forest_clf.predict([some_digit]) # array([5.])
forest_clf.predict_proba([some_digit])
# array([[0.04, 0. , 0.02, 0.05, 0. , 0.88, 0. , 0. , 0.01, 0. ]])
# label 5 的概率最大6. 误差分析
6.1 检查混淆矩阵
使用cross_val_predict()做出预测然后调用confusion_matrix()函数
y_train_pred cross_val_predict(sgd_clf, X_train, y_train, cv3)
conf_mat confusion_matrix(y_train, y_train_pred)
conf_matarray([[5777, 0, 24, 21, 10, 19, 22, 4, 36, 10],[ 3, 6478, 48, 46, 12, 25, 12, 14, 83, 21],[ 91, 71, 5088, 235, 38, 40, 77, 64, 235, 19],[ 56, 26, 185, 5376, 6, 160, 32, 62, 143, 85],[ 41, 34, 69, 49, 5055, 36, 64, 40, 174, 280],[ 95, 27, 66, 430, 65, 4243, 98, 23, 275, 99],[ 101, 20, 82, 14, 31, 98, 5501, 3, 58, 10],[ 38, 27, 88, 79, 47, 21, 5, 5650, 33, 277],[ 61, 130, 96, 469, 31, 240, 40, 39, 4587, 158],[ 51, 34, 50, 250, 141, 80, 1, 330, 289, 4723]],dtypeint64)用图像展现混淆矩阵
plt.matshow(conf_mat, cmapplt.cm.gray)白色主要在对角线上意味着被分类正确。 数字 5 对应的格子比其他的要暗。两种可能数据5比较少数据5预测不准确
row_sums conf_mat.sum(axis1, keepdimsTrue)
norm_conf_mat conf_mat/row_sums # 转成概率
np.fill_diagonal(norm_conf_mat, 0) # 对角线的抹去
plt.matshow(norm_conf_mat, cmapplt.cm.gray)
plt.show()只保留被错误分类的数据再查看错误分布 可以看出数字被错误的预测成3、8、9的较多
把3和5的预测情况拿出来分析
def plot_digits(instances, images_per_row10, **options):size 28images_per_row min(len(instances), images_per_row)images [instance.reshape(size,size) for instance in instances]n_rows (len(instances) - 1) // images_per_row 1row_images []n_empty n_rows * images_per_row - len(instances)images.append(np.zeros((size, size * n_empty)))for row in range(n_rows):rimages images[row * images_per_row : (row 1) * images_per_row]row_images.append(np.concatenate(rimages, axis1))image np.concatenate(row_images, axis0)plt.imshow(image, cmap plt.cm.binary, **options)plt.axis(off)cl_a, cl_b 3, 5
X_aa X_train[(y_train cl_a) (y_train_pred cl_a)]
X_ab X_train[(y_train cl_a) (y_train_pred cl_b)]
X_ba X_train[(y_train cl_b) (y_train_pred cl_a)]
X_bb X_train[(y_train cl_b) (y_train_pred cl_b)]
plt.figure(figsize(8,8))
plt.subplot(221); plot_digits(np.array(X_aa[:25]), images_per_row5)
plt.subplot(222); plot_digits(np.array(X_ab[:25]), images_per_row5)
plt.subplot(223); plot_digits(np.array(X_ba[:25]), images_per_row5)
plt.subplot(224); plot_digits(np.array(X_bb[:25]), images_per_row5)
plt.show()原因3 和 5 的不同像素很少所以模型容易混淆 3 和 5 之间的主要差异是连接顶部的线和底部的线的细线的位置。 如果你画一个 3连接处稍微向左偏移分类器很可能将它分类成5。反之亦然。换一个说法这个分类器对于图片的位移和旋转相当敏感。 所以减轻 3、5 混淆的一个方法是对图片进行预处理确保它们都很好地中心化和不过度旋转。这同样很可能帮助减轻其他类型的错误。