温岭专业营销型网站建设地址,企业网站模板下载价格多少,400套商业网站的静态模板,文山app开发定制目的#xff1a;使用 MNIST 数据集#xff0c;建立数字图像识别模型#xff0c;识别任意图像中的数字#xff1b; 文章目录1. 数据准备#xff08;MNIST#xff09;2. 二元分类器#xff08;SGD#xff09;3. 性能测试1. 交叉验证2. 混淆矩阵3. 查准率与查全率4. P-R 曲…目的使用 MNIST 数据集建立数字图像识别模型识别任意图像中的数字 文章目录1. 数据准备MNIST2. 二元分类器SGD3. 性能测试1. 交叉验证2. 混淆矩阵3. 查准率与查全率4. P-R 曲线5. ROC 曲线6. RandomForestClassifier vs. SGDClassifier4. 多类分类器5. 误差分析6. 多标签分类7. 多输出分类1. 消除图片中的噪声1. 数据准备MNIST
MNIST一组由美国高中生和人口调查局员工手写的 70000 个数字图片每张图片都用其代表的数字标记因广泛被应用于机器学习入门被称作机器学习领域的 Hello World也可用于测试新分类算法的效果
使用 Scikit-Learn 下载数据集的前置工作
import ssl
ssl._create_default_https_context ssl._create_unverified_contextScikit-Learn 使用 Python 的 urllib 包通过 HTTPS 协议下载数据集这里全局取消证书验证否则 Scikit-Learn 可能无法建立 ssl 连接
使用 Scikit-Learn 下载 MNIST
from sklearn.datasets import fetch_openml
mnist fetch_openml(mnist_784, version1)
mnist.keys()dict_keys([data, target, frame, categories, feature_names, target_names, DESCR, details, url])### 查看数组
X, y mnist[data], mnist[target]
X.shape(70000, 784)y.shape
(70000,)共 70000 张图片每张图片由 784 个特征28 * 28 个像素每个像素用 0(白色) 到 255(黑色) 表示
Scikit-Learn 数据集通用字典结构
DESCR描述数据集data包含一个数组每个实例为一行每个特征为一列target包含一个带有标记的数组
使用 Matplotlib 查看数字图片
编写绘图函数
import matplotlib.pyplot as plt
import matplotlib as mpldef plot_digit(data):image data.reshape(28, 28)plt.imshow(image, cmap mpl.cm.binary, interpolationnearest)plt.axis(off)def plot_digits(instances, images_per_row10, **options):size 28images_per_row min(len(instances), images_per_row)# This is equivalent to n_rows ceil(len(instances) / images_per_row):n_rows (len(instances) - 1) // images_per_row 1# Append empty images to fill the end of the grid, if needed:n_empty n_rows * images_per_row - len(instances)padded_instances np.concatenate([instances, np.zeros((n_empty, size * size))], axis0)# Reshape the array so its organized as a grid containing 28×28 images:image_grid padded_instances.reshape((n_rows, images_per_row, size, size))# Combine axes 0 and 2 (vertical image grid axis, and vertical image axis),# and axes 1 and 3 (horizontal axes). We first need to move the axes that we# want to combine next to each other, using transpose(), and only then we# can reshape:big_image image_grid.transpose(0, 2, 1, 3).reshape(n_rows * size, images_per_row * size)# Now that we have a big image, we just need to show it:plt.imshow(big_image, cmap mpl.cm.binary, **options)plt.axis(off)MNIST 的第一个图片展示
some_digit X[:1].to_numpy()
plot_digit(some_digit)
plt.show()# 查看图片对应标签验证是一个数字 5
y[0]5MNIST 的多图样例展示
plt.figure(figsize(9,9))
example_images X[:100]
plot_digits(example_images, images_per_row10)
# save_fig(more_digits_plot)
plt.show()将字符标签转换成整数
import numpy as npy y.astype(np.uint8)创建测试集
X_train, X_test, y_train, y_test X[:60000], X[60000:], y[:60000], y[60000:]MNIST 数据集已经分成训练集前 6 万张图片和测试集最后 1 万张图片
可以对训练集进行混洗保障在做交叉验证时所有折叠的实例分布相当有一些算法对训练实例的顺序敏感连续输入相同的实例可能导致性能不佳也有一些情况时间序列也是实例特征如股市架构或天气状态则不可混洗数据集
2. 二元分类器SGD
二元分类器在两个类中区分
简化问题图片数字识别先从识别图片 是 5 和 非 5 开始
转换图片的标签
y_train_5 (y_train 5) # True for all 5s, False for all other digits
y_test_5 (y_test 5)使用 Scikit-Learn 的 SGDClassifier 训练随机梯度下降SGD分类器
SGD独立处理训练实例一次一个非常适合处理大型的数据集也适合在线学习
from sklearn.linear_model import SGDClassifiersgd_clf SGDClassifier(random_state42)
sgd_clf.fit(X_train, y_train_5)给 random_state 设置固定值如 42 可以让 SGD 的随机训练变得结果可复现
sgd_clf.predict(X[:1])array([ True])SGD 分类器预测这是一张 5结果正确
3. 性能测试
准确率正确预测的比率
1. 交叉验证
自定义实现交叉验证
from sklearn.model_selection import StratifiedKFold
from sklearn.base import cloneskfolds StratifiedKFold(n_splits3, random_state42, shuffleTrue)for train_index, test_index in skfolds.split(X_train, y_train_5):clone_clf clone(sgd_clf)X_train_folds X_train.iloc[train_index]y_train_folds y_train_5.iloc[train_index]X_test_fold X_train.iloc[test_index]y_test_fold y_train_5.iloc[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.9669
0.91625
0.96785StratifiedKFold实现分层抽样让每个折叠中各个类的比例与整体比例相当clone为每个迭代创建一个分类器的副本用于对训练集的训练和测试集的预测
使用 Scikit-Learn 的 cross_val_score() 实现 K-折交叉验证
from sklearn.model_selection import cross_val_score
cross_val_score(sgd_clf, X_train, y_train_5, cv3, scoringaccuracy)array([0.95035, 0.96035, 0.9604 ])K-折交叉验证将训练集分解成 K 个折叠这里是 3 折每次留 1 个折叠用于测试集剩余用于训练集
所有折叠交叉验证的准确率都超过了 91%这看似很准确实则准确率不足以衡量这个分类器的优劣
自定义 非 5 分类器
from sklearn.base import BaseEstimatorclass Never5Classifier(BaseEstimator):def fit(self, X, yNone):return selfdef predict(self, X):return np.zeros((len(X), 1), dtypebool)never_5_clf Never5Classifier()
cross_val_score(never_5_clf, X_train, y_train_5, cv3, scoringaccuracy)array([0.91125, 0.90855, 0.90915])使用自定义 非 5 分类器进行交叉验证得到所有折叠的准确率也在 90% 以上这是因为所有图片中只有约 10% 是数字 590% 非 5 是正确的这进一步说明准确率不足以评判分类器的性能特别是处理有偏数据集时
2. 混淆矩阵 混淆矩阵对多个二分类或多分类进行训练/测试统计 A 类实例被分类为 B 类别的次数是评估分类器性能的常见方法 使用 cross_val_predict() 进行 K-折交叉预测
from sklearn.model_selection import cross_val_predicty_train_pred cross_val_predict(sgd_clf, X_train, y_train_5, cv3)cross_val_predict 与 cross_val_score 类似但返回的不是交叉验证的评分而是每个折叠的预测值
使用 confusion_matrix() 获取混淆矩阵
from sklearn.metrics import confusion_matrixconfusion_matrix(y_train_5, y_train_pred)array([[53892, 687],[ 1891, 3530]])混淆矩阵的行表示实际类别实际为 非 5、5列表示预测类别预测为 非 5、5 负类Negative实际为非 5 真负类TN53892 个正确分类为非 5假正类FP687 个错误分类为 5 正类Positive实际为 5 假负类FN1891 个错误分类为 非 5真正类TP3530 个正确分类为 5
完美的分类器只存在真正类与真负类混淆矩阵的对角线左上和右下有非零值
y_train_perfect_predictions y_train_5 # pretend we reached perfection
confusion_matrix(y_train_5, y_train_perfect_predictions)array([[54579, 0],[ 0, 5421]])3. 查准率与查全率
查准率(precision)真正类占真正类和假正类之和的比例将忽略这个正类实例之外的所有内容
precisionTPTPFPprecision \frac{TP}{TP FP} precisionTPFPTP
查全率(recall): 召回率灵敏度或真正类率真正类占所有正类真正类和假负类之和的比例正确检测到的正类实例的比率
recallTPTPFNrecall \frac{TP}{TP FN} recallTPFNTP
使用 Scikit-Learn 计算查准率和查全率
from sklearn.metrics import precision_score, recall_scoreprecision_score(y_train_5, y_train_pred) # 3530 / (3530 687)0.8370879772350012recall_score(y_train_5, y_train_pred) # 3530 / (3530 1891)0.6511713705958311这说明当这个 5-检测器 说一张图片是 5 时只有 83% 时准确的且只有 65% 的 5 被检测出来了
F1F_1F1 分数查准率与查全率的谐波平均值会给予低值更高的权重更适用于查准率和查全率相近的分类器
F121precision1recall2×precision×recallprecisionrecallTPTPFNFP2F_1 \frac{2}{\frac{1}{precision} \frac{1}{recall}} 2 \times \frac{precision \times recall}{precision recall} \frac{TP}{TP \frac{FN FP}{2}} F1precision1recall122×precisionrecallprecision×recallTP2FNFPTP
使用 f1_score() 计算 F1F_1F1 分数
from sklearn.metrics import f1_scoref1_score(y_train_5, y_train_pred)0.7325171197343846鱼与熊掌不可得兼不能同时兼顾查准率和查全率 对于宁缺毋滥类型的分类器更在乎查准率如给小孩子推荐视频 对于宁杀错不放过类型的分类器更在乎查全率如小区监控抓小偷
4. P-R 曲线
P-R 曲线将实例按预测为正类的概率高低排序然后逐个把样本作为正类进行预测评估计算其查准率和查全率以查全率为横轴查准率为纵轴绘制一个曲线图
SGDClassifier 的分类决策 基于决策函数计算处每个实例的分值将每个实例按分数从低到高从左到右排列取一个阈值大于该阈值的实例为正类否则为负类通常阈值越高查全率越低查准率越高
若决策阈值在中间箭头位置两个 5 之间查准率为 80%4/5查全率为 67%4/6若决策阈值在右边箭头位置提升阈值查准率为 100%3/3查全率为 50%3/6若决策阈值在左边箭头位置降低阈值查准率为 75%6/8查全率为 100%6/6
使用 decision_function() 获取每个实例的分数
y_scores sgd_clf.decision_function(some_digit)
y_scoresarray([2164.22030239])通过阈值控制预测结果
threshold 0
y_some_digit_pred (y_scores threshold)
y_some_digit_predarray([ True])提升阈值控制预测结果
threshold 8000
y_some_digit_pred (y_scores threshold)
y_some_digit_predarray([False])提升阈值可以降低查全率将本是 5 的图片判定为了非 5
使用 cross_val_predict() 获取训练集的实例分数
y_scores cross_val_predict(sgd_clf, X_train, y_train_5, cv3, methoddecision_function)使用 precision_recall_curve() 计算所有阈值对应的查准率和查全率
from sklearn.metrics import precision_recall_curveprecisions, 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, linewidth2)plt.plot(thresholds, recalls[:-1], g-, labelRecall, linewidth2)plt.legend(loccenter right, fontsize16)plt.xlabel(Threshold, fontsize16)plt.grid(True)plt.axis([-50000, 50000, 0, 1])recall_90_precision recalls[np.argmax(precisions 0.90)]
threshold_90_precision thresholds[np.argmax(precisions 0.90)]plt.figure(figsize(8, 4))
plot_precision_recall_vs_threshold(precisions, recalls, thresholds)
plt.plot([threshold_90_precision, threshold_90_precision], [0., 0.9], r:)
plt.plot([-50000, threshold_90_precision], [0.9, 0.9], r:)
plt.plot([-50000, threshold_90_precision], [recall_90_precision, recall_90_precision], r:)
plt.plot([threshold_90_precision], [0.9], ro)
plt.plot([threshold_90_precision], [recall_90_precision], ro)
plt.show()查准率比查全率曲线要崎岖一些因为随着阈值的提升查准率可能会下降但查全率只会下降
绘制 P/R 曲线
以查全率为横轴查准率为纵轴将上文决策阈值关系图转化成一张 P-R 曲线
def plot_precision_vs_recall(precisions, recalls):plt.plot(recalls, precisions, b-, linewidth2)plt.xlabel(Recall, fontsize16)plt.ylabel(Precision, fontsize16)plt.axis([0, 1, 0, 1])plt.grid(True)plt.figure(figsize(8, 6))
plot_precision_vs_recall(precisions, recalls)
plt.plot([recall_90_precision, recall_90_precision], [0., 0.9], r:)
plt.plot([0.0, recall_90_precision], [0.9, 0.9], r:)
plt.plot([recall_90_precision], [0.9], ro)
plt.show()查全率在 80% 之后查准率急剧下降说明可能需要在此之前选择一个权衡点
通常若学习器 A 的 P-R 曲线能完全包住学习器 B 的则可断言 A 优于 B若存在交叉可采用面积比较法或平衡点比较法
查找指定查准率/查全率的最低/最高阈值 threshold_90_precision thresholds[np.argmax(precisions 0.90)]
3370.0194991439557 # 第一个 True 的最大索引 threshold_90_recall thresholds[np.argmin(recalls 0.90)]
-6861.032537940274 # 第一个 True 的最小索引使用实例分数与阈值进行预测 y_train_pred_90 (y_scores threshold_90_precision)array([False, False, False, ..., True, False, False])查看预测的查准率与查全率 precision_score(y_train_5, y_train_pred_90)
0.9000345901072293 recall_score(y_train_5, y_train_pred_90)
0.4799852425751706查准率确实是指定的 90%
5. ROC 曲线 ROCReceiver Operating Characteristic, 受试者工作特征以真正类率为纵轴以假正类率为横轴描述的是查全率与1 - 特异度的关系与 P-R 图相似若学习器 A 的曲线完全包住学习器 B 的曲线则可可断言 A 优于 B 真正类率查全率、灵敏度、召回率、True Positive RateTPR TPTPFN\frac{TP}{TP FN}TPFNTP所有正类中被测出来的正类的概率 假正类率False Positive RateFPR FPTNFP\frac{FP}{TN FP}TNFPFP所有负类中被错认为正类的概率 真负类率TNR特异率正确被分类为负类的负类实例比率
使用 roc_curve() 计算多种阈值的 TPR 和 FPR
from sklearn.metrics import roc_curvefpr, tpr, thresholds roc_curve(y_train_5, y_scores)通过 Matplotlib 绘制 ROC 曲线
def plot_roc_curve(fpr, tpr, labelNone):plt.plot(fpr, tpr, linewidth2, labellabel)plt.plot([0, 1], [0, 1], k--) # dashed diagonalplt.axis([0, 1, 0, 1])plt.xlabel(False Positive Rate (Fall-Out), fontsize16)plt.ylabel(True Positive Rate (Recall), fontsize16)plt.grid(True)plt.figure(figsize(8, 6))
plot_roc_curve(fpr, tpr)
fpr_90 fpr[np.argmax(tpr recall_90_precision)]
plt.plot([fpr_90, fpr_90], [0., recall_90_precision], r:)
plt.plot([0.0, fpr_90], [recall_90_precision, recall_90_precision], r:)
plt.plot([fpr_90], [recall_90_precision], ro)
plt.show()召回率TPR越高分类器的假正类FPR就越多虚线表示纯随机分类器的 ROC 曲线越高于虚线的 ROC 曲线对应的分类器越优
使用 Scikit-Learn 计算 ROC 的 AUC
AUCArea Under ROC CurveROC 曲线下的面积当 ROC 曲线相交时可通过 AUC 判定学习器的好坏
from sklearn.metrics import roc_auc_score roc_auc_score(y_train_5, y_scores)
0.9604938554008616这里 ROC AUC 分值看着很高是因为正类数字 5比负类非 5的数量少很多
P-R 曲线与 ROC 曲线的选择
当正类非常少见或者更关注假正类而非假负类是选择 P-R 曲线反之选择 ROC 曲线
6. RandomForestClassifier vs. SGDClassifier
RandomForestClassifier 没有 decision_function()代替的是 dict_proba()
dict_proba()返回一个数组每行代表一个实例每列表示一个类别代表某个实例属于某个给定类别的概率
训练 RandomForestClassifier 分类器
from sklearn.ensemble import RandomForestClassifierforest_clf RandomForestClassifier(random_state42)
y_probas_forest cross_val_predict(forest_clf, X_train, y_train_5, cv3, methodpredict_proba)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)这里将正类率作为分数传递给 roc_curve()
绘制 RandomForestClassifier 分类器的 ROC 曲线
plt.plot(fpr, tpr, b:, labelSGD)
plot_roc_curve(fpr_forest, tpr_forest, Random Forest)
plt.legend(loclower right)
plt.show()RandomForestClassifier 的 ROC 曲线比 SGDClassifier 好很多
# ROC AUC 分数roc_auc_score(y_train_5, y_scores_forest)
0.9983436731328145# 查准率
y_train_pred_forest cross_val_predict(forest_clf, X_train, y_train_5, cv3)precision_score(y_train_5, y_train_pred_forest)
0.9905083315756169# 查全率召回率recall_score(y_train_5, y_train_pred_forest)
0.8662608374838591RandomForestClassifier 的效果确实好很多查准率与查全率都比较高
4. 多类分类器
多元分类器多项分类器在两个以上的类别中区分
随机森林、朴素贝叶斯等分类器可以直接处理多个类支持向量机、线性分类器则是严格的二元分类器但是可以通过一些策略让二院分类器实现多分类的目的
OvR一对剩余一对多one-versus-all训练 10 个二元分类器0-检测器、1-检测器、2-检测器…当需要检测一张图片时先获取每个分类器的决策分数哪个分类器的分值最高图片归为哪一类OvO一对一训练 N×(N−1)2\frac{N \times (N - 1)}{2}2N×(N−1) 个分类器为每一对数字训练一个二元分类器0-1 分类器、0-2 分类器、1-2 分类器…优点是每个分类器只需要用到部分训练集对其必须区分的两个类进行训练
支持向量机在数据规模较大时表现较差因此应优先选择 OvO 策略但对于大多数二分类器来书OvR 是更好的选择
使用 Scikit-Learn 训练 SVM 分类器 from sklearn.svm import SVCsvm_clf SVC()svm_clf.fit(X_train, y_train) # y_train, not y_train_5svm_clf.predict([some_digit])
array([5], dtypeuint8)Scikit-Learn 检测到尝试使用二元分类算法进行多类分类任务时会自动运行 OvR 或 OvO
这里 Scikit-Learn 实际训练了 45 个二元分类器获得它们对图片的决策分数然后选择了分数最高的类
使用 decision_function() 查看 SVM 分类器的分数 some_digit_scores svm_clf.decision_function(some_digit)some_digit_scores
array([[ 1.72501977, 2.72809088, 7.2510018 , 8.3076379 , -0.31087254,9.3132482 , 1.70975103, 2.76765202, 6.23049537, 4.84771048]])查看分数最高的分类 np.argmax(some_digit_scores)
5svm_clf.classes_
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtypeuint8)svm_clf.classes_[5]
5classes_存储目标类的列表按值的大小排序索引与类值不一定相同
强制使用 OneVsRestClassifier 策略训练 SVC 多类分类器 from sklearn.multiclass import OneVsRestClassifierovr_clf OneVsRestClassifier(SVC())ovr_clf.fit(X_train, y_train)ovr_clf.predict(some_digit)
array([5], dtypeuint8)len(ovr_clf.estimators_)
10OneVsRestClassifierOvR 策略实现类OneVsOneClassifierOvO 策略实现类
训练 SGDClassifier 的多类分类器 sgd_clf.fit(X_train, y_train)sgd_clf.predict([some_digit])
array([3], dtypeuint8)SGC 分类器可以直接将实例分为多个类不必运行 OvR 或 OvO
使用 decision_function() 计算每个实例分类为每个类的概率 sgd_clf.decision_function(some_digit)
array([[-31893.03095419, -34419.69069632, -9530.63950739,1823.73154031, -22320.14822878, -1385.80478895,-26188.91070951, -16147.51323997, -4604.35491274,-12050.767298 ]])第 3 类得分 1823其他都是负分值预测错误实际是 5
使用 scross_val_score() 评估 SGDClassifier 的准确性 cross_val_score(sgd_clf, X_train, y_train, cv3, scoringaccuracy)
array([0.87365, 0.85835, 0.8689 ])每个折叠的准确率在 85% 以上随机分类器准确率约为 10%
通过缩放对 SGD 分离进行优化 from sklearn.preprocessing import StandardScalerscaler StandardScaler()X_train_scaled scaler.fit_transform(X_train.astype(np.float64))cross_val_score(sgd_clf, X_train_scaled, y_train, cv3, scoringaccuracy)
array([0.8983, 0.891 , 0.9018])简单缩放训练集数据后准确率提升到 89%
5. 误差分析
使用 cross_val_predict() 进行预测并计算混淆矩阵 y_train_pred cross_val_predict(sgd_clf, X_train_scaled, y_train, cv3)conf_mx confusion_matrix(y_train, y_train_pred)conf_mx
array([[5577, 0, 22, 5, 8, 43, 36, 6, 225, 1],[ 0, 6400, 37, 24, 4, 44, 4, 7, 212, 10],[ 27, 27, 5220, 92, 73, 27, 67, 36, 378, 11],[ 22, 17, 117, 5227, 2, 203, 27, 40, 403, 73],[ 12, 14, 41, 9, 5182, 12, 34, 27, 347, 164],[ 27, 15, 30, 168, 53, 4444, 75, 14, 535, 60],[ 30, 15, 42, 3, 44, 97, 5552, 3, 131, 1],[ 21, 10, 51, 30, 49, 12, 3, 5684, 195, 210],[ 17, 63, 48, 86, 3, 126, 25, 10, 5429, 44],[ 25, 18, 30, 64, 118, 36, 1, 179, 371, 5107]])使用 Matplotlib 的 matshow() 查看混淆矩阵
plt.matshow(conf_mx, cmapplt.cm.gray)
plt.show()大多数图片被分到对角线上说明它们被正确分类了数字 5 略暗说明可能数字 5 较少也可能数字 5 的分类效果不如其他数字
将混淆矩阵中的每个值除以相应类中的图片数量这样比较的就是错误率而非错误的绝对值
row_sums conf_mx.sum(axis1, keepdimsTrue)
norm_conf_mx conf_mx / row_sums重新绘制混淆矩阵效果图
用 0 填充对角线只看错误部分
np.fill_diagonal(norm_conf_mx, 0)
plt.matshow(norm_conf_mx, cmapplt.cm.gray)
plt.show()每行代表实际类、每列代表预测类
第 8 列比较亮说明许多图片被错误的分类为了 8 改进数字 8 的分类错误可以试着收集更多像数字 8 的训练数据以便分类器学会将它们与真实的数字 8 区分开也可以开发一些新特征用来改进分类器计算闭环的数量如 8 有两个、6 有一个、5 没有还可以对图片进行预处理Scikit-Image、Pillow、OpenCV 等让某些模式更为突出如闭环等 数字 3 和数字 5 经常被混淆两个方向的交叉处较亮 可以分析单个错误示例在做什么为何失败
查看数字 3 和数字 5
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(X_aa[:25], images_per_row5)
plt.subplot(222); plot_digits(X_ab[:25], images_per_row5)
plt.subplot(223); plot_digits(X_ba[:25], images_per_row5)
plt.subplot(224); plot_digits(X_bb[:25], images_per_row5)
plt.show()左侧两个 5×55 \times 55×5 矩阵显示了呗分类为数字 3 的图片右侧两个 5×55 \times 55×5 矩阵显示了被分类为数字 5 的图片左下和右上为分类错误示例
SGD 是一个简单的线性模型它为每一个像素分配一个各个类别的权重当它看到新图片时将加权后的 像素强度汇总从而得到一个分数进行分类而 3 和 5 的像素位大多重叠因此容易混淆
减少 3 和 5 之间混淆的方式可以是对图片进行预处理如确保他们在中心位置且没有选择
6. 多标签分类
多标签分类分类器为每个实例输出多个类如一张图片识别出多个人
使用 KNeighborsClassifier 创建多标签分类
KNeighborsClassifier支持多标签分类不是所有分类器都支持 from sklearn.neighbors import KNeighborsClassifiery_train_large (y_train 7) # 大数标签y_train_odd (y_train % 2 1) # 奇数标签y_multilabel np.c_[y_train_large, y_train_odd] # 多标签数组knn_clf KNeighborsClassifier()knn_clf.fit(X_train, y_multilabel)knn_clf.predict(some_digit)
array([[False, True]])分类正确数字 5 不是大数是奇数
多标签分类器的性能评估 y_train_knn_pred cross_val_predict(knn_clf, X_train, y_multilabel, cv3)f1_score(y_multilabel, y_train_knn_pred, averagemacro)
0.976410265560605假设所有标签都同等重要可以通过测量每个标签的 F1F_1F1 分数或其他任何二元分类器指标并计算它们的平均分数
但实际往往并发如此比如识别图片中的多个人其中有的人可能拍了很多照片那这个人的权重就要高很多这时需要给每个标签设置一个相当的权重可以是具有该目标标签的实例的数量
7. 多输出分类
多输出分类或称多输出多分类是多标签分类的泛化其标签也可以是多类的
1. 消除图片中的噪声
目标构建一个系统输入一张有噪声的图片系统输出一张干净的数字图片
分类和回归之间有时是模糊的这个示例即可一说是多输出分类任务也可以说是像素强度的回归任务
使用 NumPy 的 randint() 为 MNIST 图片添加噪声
noise np.random.randint(0, 100, (len(X_train), 784))
X_train_mod X_train noise
noise np.random.randint(0, 100, (len(X_test), 784))
X_test_mod X_test noise
y_train_mod X_train
y_test_mod X_test查看图片样例
plt.subplot(121)
plot_digit(X_test_mod[:1].to_numpy())
plt.subplot(122)
plot_digit(y_test_mod[:1].to_numpy())
plt.show()通过训练分类器清洗噪声图片
knn_clf.fit(X_train_mod, y_train_mod)
clean_digit knn_clf.predict(X_test_mod[:1].to_numpy())
plot_digit(clean_digit)清洗后的效果与原图相近了 上一篇「ML 实践篇」回归系统房价中位数预测专栏《机器学习》
PS欢迎各路道友阅读与评论感谢道友点赞、关注、收藏 参考资料
[1]《机器学习》[2]《机器学习实战》