学习笔记:MNIST数据集
来源:互联网 发布:网络摄像头的安装方法 编辑:程序博客网 时间:2024/06/06 02:08
数据预览
sklearn中内置了从开放数据库中取得数据集的方法,在线导入MNIST数据集。
from sklearn.datasets import fetch_mldatamnist = fetch_mldata('MNIST original')mnist
数据是以字典格式存储的,其中’data’键值对应的为数据,’target’键值对应的为样本标签,接下来将数据与标签提取出来。
X,Y=mnist["data"],mnist["target"]print(X.shape,Y.shape)
输出为:(70000, 784) (70000,)。共有70000个样本,每个样本具有784个特征,实际上MNIST的每个样本为一张图片,这是28*28的像素特征。下面随便选取一个样本进行可视化。
numpy.reshape() : Gives a new shape to an array without changing its data.
matplotlib.pyplot.imshow() : Display an image on the axes.
Parameters:
- X : array_like, shape (n, m) or (n, m, 3) or (n, m, 4).
- cmap : Colormap.
- interpolation : Acceptable values are ‘none’, ‘nearest’, ‘bilinear’, ‘bicubic’, ‘spline16’, ‘spline36’, ‘hanning’, ‘hamming’, ‘hermite’, ‘kaiser’, ‘quadric’, ‘catrom’, ‘gaussian’, ‘bessel’, ‘mitchell’, ‘sinc’, ‘lanczos’.
%matplotlib inlineimport matplotlibfrom matplotlib import pyplot as pltindex=36000 #随便选一个样本some_digit=X[index]print(type(some_digit))some_digit_image=some_digit.reshape(28,28)plt.imshow(some_digit_image,cmap=matplotlib.cm.binary,interpolation="nearest")plt.axis("off") #关闭坐标轴plt.show()print(Y[index])
输出为5.0。
划分数据集
MNIST数据集是已经划分好训练集与测试集的,直接提取然后打乱顺序即可。注意测试集不需要打乱顺序。
numpy.random.permutation() : Randomly permute a sequence, or return a permuted range. If x is a multi-dimensional array, it is only shuffled along its first index.
X_train,X_test,Y_train,Y_test=X[:60000],X[60000:],Y[:60000],Y[60000:]import numpy as npshuffle_index=np.random.permutation(60000)X_train,Y_train=X_train[shuffle_index],Y_train[shuffle_index]
二分类任务
首先考虑一个最简单的二分类问题,训练一个SGD线性分类器来判断图片中的数字是不是“5”。模型的评判标准以F1分数为准。
sklearn.model_selection.cross_val_score() : Evaluate a score by cross-validation.
Parameters:
- estimator : The object to use to fit the data.
- X : The data to fit.
- y : The target variable to try to predict in the case of supervised learning.
Y_train_bin=(Y_train==5)Y_test_bin=(Y_test==5)from sklearn.linear_model import SGDClassifiersgd_clf=SGDClassifier(random_state=42)sgd_clf.fit(X_train,Y_train_bin)from sklearn.model_selection import cross_val_scorecross_val_score(sgd_clf,X_train,Y_train_bin,cv=3,scoring="f1")
输出为:array([ 0.7653012 , 0.78112633, 0.76090226])
模型评估
准确率/召回率权衡
准确率指的是模型预测的正例中有多少是对的,而召回率指的是整个数据集中的正例有多少被模型找出来了,也称查全率。一般来说,准确率和召回率是互相矛盾的两个量。
sklearn.model_selection.cross_val_predict() : Generate cross-validated estimates for each input data point.
Parameters:
- method : string, optional.当选项为”decision_function”时会返回每个样本的得分。
sklearn.metrics.precision_recall_curve() : Compute precision-recall pairs for different probability thresholds.This implementation is restricted to the binary classification task.
Parameters:
- y_true : True targets of binary classification in range {-1, 1} or {0, 1}.
- probas_pred : Estimated probabilities or decision function.
Returns:
- precision
- recall
- thresholds,当模型给某一样本打出的分数高于此值则会判为正例
Note: there is an issue introduced in Scikit-Learn 0.19.0 where the result of cross_val_predict()
is incorrect in the binary classification case when using method="decision_function"
, as in the code above. The resulting array has an extra first dimension full of 0s. We need to add this small hack for now to work around this issue.
from sklearn.model_selection import cross_val_predictY_scores=cross_val_predict(sgd_clf,X_train,Y_train_bin,cv=3,method="decision_function") #针对每个样本给出预测值# hack to work around issue #9589 introduced in Scikit-Learn 0.19.0if Y_scores.ndim == 2: Y_scores = Y_scores[:, 1]from sklearn.metrics import precision_recall_curveprecisions,recalls,thresholds=precision_recall_curve(Y_train_bin,Y_scores)
def plot_precision_recall_vs_thresholds(precisions,recalls,thresholds): #注意此处绘制时precisions与recalls均不包含最后一个值 plt.plot(thresholds,precisions[:-1],"b--",label="Precison") plt.plot(thresholds,recalls[:-1],"g-",label="Recall") plt.xlabel("Threshould") plt.legend(loc="best") plt.axis([-650000,650000,0,1])plot_precision_recall_vs_thresholds(precisions,recalls,thresholds)plt.show()
召回率是严格关于阈值的减函数,但是准确率在一定范围内是关于阈值的增函数,但并不是阈值的全局增函数。
准确率与召回率的关系。
def plot_recall_vs_precision(recalls,precisions): plt.plot(recalls,precisions,"k") plt.xlabel("Recall") plt.ylabel("Precision") plt.axis([0,1,0,1])plot_recall_vs_precision(recalls,precisions)plt.show()
ROC曲线
另一种评估模型的方法是计算模型ROC曲线下的面积,ROC曲线评估的是假正例率与真正例率。
sklearn.metrics.roc_curve() : Compute Receiver operating characteristic (ROC).This implementation is restricted to the binary classification task.
Returns:
- fpr
- tpr
- thresholds
from sklearn.metrics import roc_curvefpr,tpr,thresholds=roc_curve(Y_train_bin,Y_scores)
def plot_roc_curve(fpr,tpr,label=None): plt.plot(fpr,tpr,linewidth=2,label=label) plt.axis([0,1,0,1]) plt.xlabel("False Positive Rate") plt.ylabel("True Positive Rate")plot_roc_curve(fpr,tpr)plt.show()
更换模型
使用SGD的线性模型表现并不是很好,更换集成模型中的随机森林试试。
sklearn.model_selection.cross_val_predict() : Generate cross-validated estimates for each input data point.
from sklearn.ensemble import RandomForestClassifierforest_clf=RandomForestClassifier(random_state=42)Y_probas_forest=cross_val_predict(forest_clf,X_train,Y_train_bin,cv=3,method="predict_proba")Y_scores_forest=Y_probas_forest[:,1]fpr_forest,tpr_forest,threshold_forest=roc_curve(Y_train_bin,Y_scores_forest)
对比线性模型与随机森林的ROC曲线。
plt.plot(fpr,tpr,"b:",label="sgd")plot_roc_curve(fpr_forest,tpr_forest,"Random Forest")plt.legend(loc="best")plt.show()
多分类任务
要完成多分类任务,最简单的方法就是训练多个二分分类器,然后用这些二分分类器来完成多分类任务。但实际上有些分类器,如随机森林分类器,直接就能够处理多分类任务,不需要生成额外的分类器。
from sklearn.ensemble import RandomForestClassifierforest_clf=RandomForestClassifier(random_state=42)forest_clf.fit(X_train,Y_train)forest_clf.predict_proba([some_digit])
输出为:array([[ 0. , 0. , 0. , 0.1, 0. , 0.9, 0. , 0. , 0. , 0. ]])。模型在数字’5’对应的位置给出了最高的预测概率,与实际相符。
训练多个分类器的策略又分为两种,一对一(OvO)与一对多(OvA)。OvO策略会生成
sklearn会模型训练时自动完成多分类器的创建,一般情况下会默认使用OvA策略,但是对于SVM分类器会使用OvO策略。
sgd_clf.fit(X_train,Y_train) #OvA策略sgd_clf.classes_
输出为:array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
如果需要指定创建多个分类器的策略,可以使用以下方法。
from sklearn.multiclass import OneVsOneClassifierovo_clf=OneVsOneClassifier(SGDClassifier(random_state=42))ovo_clf.fit(X_train,Y_train)print(len(ovo_clf.estimators_))
输出为45。
模型评估
多个分类器无法像单个分类器那样地使用F1分数来进行评测,这里仅使用准确率来评估模型。
cross_val_score(sgd_clf,X_train,Y_train,cv=3,scoring="accuracy")
输出为:array([ 0.85952809, 0.859943 , 0.88363254])。
对输入进行特征缩放处理,就能明显地提升模型的表现。
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,scoring="accuracy")
误差分析
混淆矩阵中的每一行代表真实标记,每一列代表预测结果。
from sklearn.metrics import confusion_matrixY_train_pred=cross_val_predict(sgd_clf,X_train_scaled,Y_train,cv=3)conf_mx=confusion_matrix(Y_train,Y_train_pred)print(conf_mx)
plt.matshow(conf_mx,cmap=plt.cm.gray) #灰度图,对应位置的值越大色块越亮plt.show()
对混淆矩阵稍微处理一下:将非对角线元素除以每行的样本总数以得到相对错误率,然后将对角线元素全部变更为0,暂时不需要被正确预测的样本。
row_sum=conf_mx.sum(axis=1,keepdims=True)norm_conf_mx=conf_mx/row_sumnp.fill_diagonal(norm_conf_mx,0)plt.matshow(norm_conf_mx,cmap=plt.cm.gray)plt.show()
可以看到图中最亮的两个块为第四行第六列与第六行第四列,即“3”与“5”这两个数字经常会被混淆。
a3p5=X_train[(Y_train==3)&(Y_train_pred==5)]a5p3=X_train[(Y_train==5)&(Y_train_pred==3)]print(len(a3p5),len(a5p3))
输出为:227 194,模型把227个’3’预测成了’5’,而把194个’5’预测成了’3’,来看一下这些被错误分类的图片。plot_digits()的实现见文末附录。
plt.figure(figsize=(8,8))plt.subplot(221)plot_digits(a3p5[:25],images_per_row=5)plt.subplot(222)plot_digits(a5p3[:25],images_per_row=5)plt.show()
左边是被误判为“5”的“3”,而右边是被误判为“3”的“5”,可以看到这些数字的书写非常潦草,个别样本人眼都很难将其区分。
KNN模型
训练一个KNN模型来完成MNIST数据集的分类任务,其最优参数使用网格搜索来确定。KNN模型的训练非常慢,此处网格搜索的参考时间达到了23个小时。
from sklearn.neighbors import KNeighborsClassifier#捷径knn_clf=KNeighborsClassifier(n_neighbors=4,weights='distance')knn_clf.fit(X_train,Y_train)#实际上应该运行下面的代码# knn_clf=KNeighborsClassifier()# from sklearn.model_selection import GridSearchCV# param_grid=[# {'n_neighbors':[3,4,5],'weights':['uniform','distance']}# ]# grid_search=GridSearchCV(knn_clf,param_grid,cv=5,scoring='accuracy',verbose=2, n_jobs=4)# grid_search.fit(X_train,Y_train)cross_val_score(sgd_clf,X_train,Y_train,cv=3,scoring="accuracy")
输出为:array([ 0.97160568, 0.97449872, 0.9713457 ]),查看模型在测试集上的性能。
from sklearn.metrics import accuracy_scoreY_knn_pred=knn_clf.predict(X_test)accuracy_score(Y_test,Y_knn_pred)
输出为:0.97140000000000004。
数据扩展
对于图片型数据,可以通过将图片移动或翻转生成的新图片加入到数据集中,实现数据集的扩充,这种方法称为数据扩展。
from scipy.ndimage.interpolation import shift#平移以ndarray格式存储的图片格式def shift_ndarray(ndarray,dx,dy): image=ndarray.reshape((28,28)) shifted_image=shift(image,[dx,dy]) return shifted_image.reshape([-1])
#ndarray列表化X_train_ex=[ndarray for ndarray in X_train]Y_train_ex=[label for label in Y_train]#移动一个像素单位top,down,left,right=(1, 0), (-1, 0), (0, 1), (0, -1)for [dx,dy] in (top,down,left,right): for ndarray,label in zip(X_train,Y_train): X_train_ex.append(shift_ndarray(ndarray,dx,dy)) Y_train_ex.append(label)#列表ndarray化X_train_ex=np.array(X_train_ex)Y_train_ex=np.array(Y_train_ex)shuffle_idx=np.random.permutation(len(X_train_ex))X_train_ex=X_train_ex[shuffle_idx]Y_train_ex=Y_train_ex[shuffle_idx]
数据扩充后的模型拟合需要一段较长的时间。
from sklearn.neighbors import KNeighborsClassifierknn_clf=KNeighborsClassifier(n_neighbors=4,weights='distance')knn_clf.fit(X_train_ex,Y_train_ex)Y_knn_pred=knn_clf.predict(X_test)from sklearn.metrics import accuracy_scoreacc=accuracy_score(Y_test,Y_knn_pred)print(acc)
输出为:0.9763。
单样本多标签分类任务
有时一个样本具有多种属性,我们需要将其具有的多种属性都预测出来。比如“5”这个数字,它是奇数,同时又小于“7”,若需要同时预测数字的这两种属性,这种任务被称为多标签分类任务。
Y_train_lager=(Y_train>=7)Y_train_odd=(Y_train%2==0)Y_multilabel=np.c_[Y_train_lager,Y_train_odd]from sklearn.neighbors import KNeighborsClassifierknn_clf=KNeighborsClassifier()knn_clf.fit(X_train_scaled,Y_multilabel)knn_clf.predict([some_digit])
输出为:array([[False, True]], dtype=bool)
附录
def plot_digits(instances, images_per_row=10, **options): size = 28 images_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 + 1 row_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, axis=1)) image = np.concatenate(row_images, axis=0) plt.imshow(image, cmap = matplotlib.cm.binary, **options) plt.axis("off")
- 学习笔记:MNIST数据集
- Caffe学习笔记(1)-MNIST数据集的准备
- 学习笔记TF056:TensorFlow MNIST,数据集、分类、可视化
- caffe学习笔记:mnist数据集的训练和测试
- 机器学习数据集-MNIST
- 机器学习数据集-MNIST
- 深度学习框架Caffe学习笔记(4)-MNIST数据集转换成可视化图片
- 学习TensorFlow,邂逅MNIST数据集
- 深度学习数据集——MNIST
- 机器学习(5) MNIST数据集
- 《MNIST学习》读取数据
- caffe学习笔记:mnist
- mnist.py学习笔记
- 深度学习Caffe实战笔记(5)Windows caffe平台跑Siamese mnist数据集
- TensorFlow官方教程学习笔记(四)——MNIST数据集的读取
- 深度学习caffe实战笔记(13)利用MATLAB可视化mnist数据集
- caffe(ubuntu14.04)学习笔记1——运行MNIST数据集模型
- TensorFlow学习笔记(1):使用softmax对手写体数字(MNIST数据集)进行识别
- 输入n个数,输出他们的平均数,以-1为结束标志
- MySQL数据库学习09-查询数据:子查询
- Spring中配置AOP出现org.springframework.beans.factory.BeanCreationException异常
- redis学习笔记1
- Window10+VS2015+DevExpress.net 15.1.7完美破解(图)
- 学习笔记:MNIST数据集
- liunx学习总结
- 块存储、文件存储、对象存储
- Maven学习总结——Maven Tomcat7自动部署
- Multibot——云上强大的多线程多功能交易平台
- KindEditor 在线编辑器 自定义文件上传与图片管理器实现
- Mac iOS com.apple.CoreSimulator.SimDeviceType.undefined
- 计算机逻辑运算实现介绍
- Java读取Excel文件