手写数字识别,机器学习“分类”学习笔记—来自Geron的《机器学习实战》
图片识别领域的“hello word”
MNIST
获取MNIST代码,70000张手写数字的图片----28x28个像素0-255黑白像素点
Scitkit-Learn 加载数据集通常为字典结构
(这里需要下载数据集,时间比较长,data_home为保存路径,事先设定好路径之后就不会找不到数据存放在那了)
from sklearn.datasets import fetch_openml
mnist = fetch_openml('mnist_784',version=1,data_home='./datasets',as_frame=False)
mnist.keys()
dict_keys(['data', 'target', 'frame', 'categories', 'feature_names', 'target_names', 'DESCR', 'details', 'url'])
注意:这里mnist = fetch_openml(‘mnist_784’,version=1,data_home=’./datasets’, as_frame=False
)这里书上是没有as_frame=False
的,当没有这句话时,后面是读不出来数据的
去查看了git-hub上的代码是这样说的
Warning: since Scikit-Learn 0.24, fetch_openml() returns a Pandas DataFrame by default. To avoid this and keep the same code as in the book, we use as_frame=False.
可见是版本更新之后出现的与数据格式的不同
X,y = mnist["data"],mnist["target"]
X.shape
(70000, 784)
y.shape
(70000,)
使用Matplotlib中的imgshow()将图片显示出来
import matplotlib as mpl
import matplotlib.pyplot as plt
some_digit = X[0]
some_digit_image = some_digit.reshape(28,28)
plt.imshow(some_digit_image,cmap="binary")
plt.axis("off")
plt.show()
y[0]
'5'
这里标签是字符,机器学习希望标签为数字
import numpy as np
y = y.astype(np.uint8)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = X[:60000],X[60000:],y[:60000],y[60000:]
训练二元分类器
从二分类问题开始,区分数字5与非5
用随机梯度下降分类器SGD,SGD优势在于能够有效处理非常大型的数据集
y_train_5=(y_train == 5)
t_test_5 = (y_test == 5)
from sklearn.linear_model import SGDClassifier
sgd_clf = SGDClassifier(random_state = 27) # 27 是随机数种子,这里自己定义就好
sgd_clf.fit(X_train,y_train_5)
SGDClassifier(random_state=27)
sgd_clf.predict([some_digit])#这里就是上面图片所示的数字5
array([ True])
性能测量
使用交叉验证测量准确率
用cross_val_score()函数来评估SGDClassifier模型,采用K折叠验证法(三个折叠)
from sklearn.model_selection import cross_val_score
cross_val_score(sgd_clf,X_train,y_train_5,cv=3,scoring="accuracy")
array([0.9436 , 0.95535, 0.9681 ])
折叠交叉的正确率超过93%,看起来很高的样子,但是如果把每一个测试集都语言成非5的话,正确率将达到90%,如下所示
from sklearn.base import BaseEstimator
class Never5Classifier(BaseEstimator):
def fit(self,X,y=None):
return self
def predict(self,X):
return np.zeros((len(X),1),dtype=bool)#预测全为0
never_5_clf = Never5Classifier()
cross_val_score(never_5_clf,X_train,y_train_5,cv=3,scoring="accuracy")
array([0.91125, 0.90855, 0.90915])
这说明用准确率通常无法成为分类器的首要性能指标,所欲需要其他的指标来评判一个预测模型的好坏
混淆矩阵
统计类别A实例被分成为实例B类别的次数
from sklearn.model_selection import cross_val_predict
y_train_pred = cross_val_predict(sgd_clf,X_train,y_train_5,cv=3)
from sklearn.metrics import confusion_matrix
confusion_matrix(y_train_5, y_train_pred)
array([[52775, 1804],
[ 855, 4566]], dtype=int64)
上面的结果矩阵就是混淆矩阵,预测非5正确的有52775个(真负类TN),将非5预测为5的有1804个(假正类FP),将5预测为非5的有855个(假负类FN)。正确预测非5的有4566个(真正类TP)。可见预测结果的准确率并不是我们想要的,但是上述的结果的准确率却高达93%,因此,我们不应该用正确率来衡量一个模型的好坏
精度和召回率
精 度 = T P T P + F P 精度=\frac{TP}{TP+FP} 精度=TP+FP