三、分类

三、分类

首先,我们导入几个常用模块,确保MatplotLib以内联方式绘制图形,并准备一个函数来保存图形。
我们还检查是否安装了Python3.5或更高版本以及Scikit Learn≥0.20。

# Python ≥3.5 
import sys
assert sys.version_info >= (3, 5)

# Scikit-Learn ≥0.20 
import sklearn
assert sklearn.__version__ >= "0.20"

# 基础库
import numpy as np
import pandas as pd
import os

# 使笔记本的输出在运行期间保持稳定
np.random.seed(42)

# 画出漂亮的图形
%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rc('axes', labelsize=14)
mpl.rc('xtick', labelsize=12)
mpl.rc('ytick', labelsize=12)

# 保存数据位置
PROJECT_ROOT_DIR = "."
CHAPTER_ID = "classification"
IMAGES_PATH = os.path.join(PROJECT_ROOT_DIR, "images", CHAPTER_ID)
os.makedirs(IMAGES_PATH, exist_ok=True)

# 保存图片
def save_fig(fig_id, tight_layout=True, fig_extension="png", resolution=300):
    path = os.path.join(IMAGES_PATH, fig_id + "." + fig_extension)
    print("Saving figure", fig_id)
    if tight_layout:
        plt.tight_layout()
    plt.savefig(path, format=fig_extension, dpi=resolution)

1 MNIST数据

from sklearn.datasets import fetch_mldata
mnist = fetch_mldata('MNIST original')

1.1 查看MNIST数据

mnist.keys()

在这里插入图片描述

X, y = mnist["data"], mnist["target"]
print(X.shape)
print(y.shape)

在这里插入图片描述

some_digit = X[3600]
some_digit_image = some_digit.reshape(28, 28)
plt.imshow(some_digit_image, cmap=mpl.cm.binary) # 
plt.axis("off")

在这里插入图片描述

y[3600]

在这里插入图片描述

y = y.astype(np.uint8)
y[3600]

在这里插入图片描述

1.2 显示手写数字

def plot_digit(data):
    image = data.reshape(28, 28)
    plt.imshow(image, cmap = mpl.cm.binary,
               interpolation="nearest")
    plt.axis("off")

plot_digit(X[3600])

在这里插入图片描述

查看数字5

np.where(y == 5)

在这里插入图片描述

plot_digit(X[30596])

在这里插入图片描述

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 = mpl.cm.binary, **options)
    plt.axis("off")

plt.figure(figsize=(9,9))
example_images = X[3600:3700]
plot_digits(example_images, images_per_row=10)
plt.show()

在这里插入图片描述

2 训练一个二分器

X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:]

y_train_5 = (y_train == 5)
y_test_5 = (y_test == 5)
y_train_5

在这里插入图片描述

打乱训练样例的顺序

shuffle_index = np.random.permutation(60000) 
X_train, y_train = X_train[shuffle_index], y_train[shuffle_index]

有毒

print('X_train.shape', X_train.shape)
print('y_train_5.shape', y_train_5.shape)

在这里插入图片描述

SGDClassifier模型

from sklearn.linear_model import SGDClassifier

sgd_clf = SGDClassifier(max_iter=1000, tol=1e-3, random_state=42)
sgd_clf.fit(X_train, y_train_5)

在这里插入图片描述

查看数字5和数字`4的图片

plot_digit(X[30590])

在这里插入图片描述

plot_digit(X[30596])

在这里插入图片描述

sgd_clf.predict([X[30590]]) # 4

在这里插入图片描述

sgd_clf.predict([X[30596]]) # 5 

在这里插入图片描述

3 对性能的评估

3.1 使用交叉验证测量准确性

分层采样StratifiedKFold

from sklearn.model_selection import StratifiedKFold
from sklearn.base import clone

skfolds = StratifiedKFold(n_splits=3, random_state=42)

for train_index, test_index in skfolds.split(X_train, y_train_5):
    clone_clf = clone(sgd_clf) # 每一次迭代,生成分类器的一个克隆版本
    X_train_folds = X_train[train_index]
    y_train_folds = y_train_5[train_index] # 训练折 训练
    X_test_fold = X_train[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)) #正确率

在这里插入图片描述

3折交叉验证cross_val_score

from sklearn.model_selection import cross_val_score

cross_val_score(sgd_clf, X_train, y_train_5, cv=3, scoring="accuracy") # accuracy 

在这里插入图片描述

非5类的表现

from sklearn.base import BaseEstimator
class Never5Classifier(BaseEstimator):
    def fit(self, X, y=None):
        pass
    def predict(self, X):
        return np.zeros((len(X), 1), dtype=bool)

never_5_clf = Never5Classifier()
cross_val_score(never_5_clf, X_train, y_train_5, cv=3, scoring="accuracy")

在这里插入图片描述

3.2 混淆矩阵#1

sklearn.model_selection.cross_val_predict:为每个输入数据点生成交叉验证的估计
使用K折交叉验证
返回基于每一个测试折做出的一个预测值

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) # 目标类 & 预测类

在这里插入图片描述

完美分类器

y_train_perfect_predictions = y_train_5 # 假装我们达到了完美
confusion_matrix(y_train_5, y_train_perfect_predictions)

在这里插入图片描述

3.3 准确率&召回率

precision_score 准确率

from sklearn.metrics import precision_score, recall_score

precision_score(y_train_5, y_train_pred)

在这里插入图片描述

recall_score 召回率

recall_score(y_train_5, y_train_pred)

在这里插入图片描述

sgd_clf.decision_function

some_digit = X[30596]
y_scores = sgd_clf.decision_function([some_digit])
y_scores

在这里插入图片描述

3.4 准确率&召回率之间的折衷

f1_score

from sklearn.metrics import f1_score
f1_score(y_train_5, y_train_pred)

在这里插入图片描述

阈值

threshold = 0
y_some_digit_pred = (y_scores > threshold)
y_some_digit_pred

在这里插入图片描述

threshold = 8000
y_some_digit_pred = (y_scores > threshold)
y_some_digit_pred

在这里插入图片描述

y_scores = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3,
                             method="decision_function")

from sklearn.metrics import 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--", label="Precision", linewidth=2)
    plt.plot(thresholds, recalls[:-1], "g-", label="Recall", linewidth=2)
    plt.legend(loc="center right", fontsize=16) # Not shown in the book
    plt.xlabel("Threshold", fontsize=16)        # Not shown
    plt.grid(True)                              # Not shown
    plt.axis([-50000, 50000, 0, 1])             # Not shown

plt.figure(figsize=(8, 4))                      # Not shown
plot_precision_recall_vs_threshold(precisions, recalls, thresholds)
plt.plot([7813, 7813], [0., 0.9], "r:")         # Not shown
plt.plot([-50000, 7813], [0.9, 0.9], "r:")      # Not shown
plt.plot([-50000, 7813], [0.4368, 0.4368], "r:")# Not shown
plt.plot([7813], [0.9], "ro")                   # Not shown
plt.plot([7813], [0.4368], "ro")                # Not shown
save_fig("precision_recall_vs_threshold_plot")  # Not shown
plt.show()

在这里插入图片描述

(y_train_pred == (y_scores > 0)).all()

在这里插入图片描述

def plot_precision_vs_recall(precisions, recalls):
    plt.plot(recalls, precisions, "b-", linewidth=2)
    plt.xlabel("Recall", fontsize=16)
    plt.ylabel("Precision", fontsize=16)
    plt.axis([0, 1, 0, 1])
    plt.grid(True)

plt.figure(figsize=(8, 6))
plot_precision_vs_recall(precisions, recalls)
plt.plot([0.4368, 0.4368], [0., 0.9], "r:")
plt.plot([0.0, 0.4368], [0.9, 0.9], "r:")
plt.plot([0.4368], [0.9], "ro")
save_fig("precision_vs_recall_plot")
plt.show()

在这里插入图片描述

达到90%的准确率

threshold_90_precision = thresholds[np.argmax(precisions >= 0.90)]
threshold_90_precision

在这里插入图片描述

y_train_pred_90 = (y_scores >= threshold_90_precision)
precision_score(y_train_5, y_train_pred_90)

在这里插入图片描述

recall_score(y_train_5, y_train_pred_90)

在这里插入图片描述

3.5 ROC 曲线

from sklearn.metrics import roc_curve

fpr, tpr, thresholds = roc_curve(y_train_5, y_scores)

def plot_roc_curve(fpr, tpr, label=None):
    plt.plot(fpr, tpr, linewidth=2, label=label)
    plt.plot([0, 1], [0, 1], 'k--') # dashed diagonal
    plt.axis([0, 1, 0, 1])                                    # Not shown in the book
    plt.xlabel('False Positive Rate (Fall-Out)', fontsize=16) # Not shown
    plt.ylabel('True Positive Rate (Recall)', fontsize=16)    # Not shown
    plt.grid(True)                                            # Not shown

plt.figure(figsize=(8, 6))                         # Not shown
plot_roc_curve(fpr, tpr)
plt.plot([4.837e-3, 4.837e-3], [0., 0.4368], "r:") # Not shown
plt.plot([0.0, 4.837e-3], [0.4368, 0.4368], "r:")  # Not shown
plt.plot([4.837e-3], [0.4368], "ro")               # Not shown
save_fig("roc_curve_plot")                         # Not shown
plt.show()

在这里插入图片描述

from sklearn.metrics import roc_auc_score

roc_auc_score(y_train_5, y_scores)

在这里插入图片描述

RandomForestClassifier ROC曲线

from sklearn.ensemble import RandomForestClassifier
forest_clf = RandomForestClassifier(n_estimators=100, random_state=42)
y_probas_forest = cross_val_predict(forest_clf, X_train, y_train_5, cv=3,
                                    method="predict_proba")

y_scores_forest = y_probas_forest[:, 1]
fpr_forest, tpr_forest, thresholds_forest = roc_curve(y_train_5,y_scores_forest)

plt.figure(figsize=(8, 6))
plt.plot(fpr, tpr, "b:", linewidth=2, label="SGD")
plot_roc_curve(fpr_forest, tpr_forest, "Random Forest")
plt.plot([4.837e-3, 4.837e-3], [0., 0.4368], "r:")
plt.plot([0.0, 4.837e-3], [0.4368, 0.4368], "r:")
plt.plot([4.837e-3], [0.4368], "ro")
plt.plot([4.837e-3, 4.837e-3], [0., 0.9487], "r:")
plt.plot([4.837e-3], [0.9487], "ro")
plt.grid(True)
plt.legend(loc="lower right", fontsize=16)
save_fig("roc_curve_comparison_plot")
plt.show()

在这里插入图片描述
roc_auc_score(y_train_5, y_scores_forest)

What happened ?

y_train_pred_forest = cross_val_predict(forest_clf, X_train, y_train_5, cv=3)
precision_score(y_train_5, y_train_pred_forest)

执行不了

recall_score(y_train_5, y_train_pred_forest)

4 多类分类(Multiclass classification)

随机森林分类器、朴素贝叶斯分类器 -> 直接处理
支持向量机分类器、线性分类器 -> 二分类器 -> 一对所有、一对一

重新加载数据集(记得Set Up)

from sklearn.datasets import fetch_mldata
mnist = fetch_mldata('MNIST original')

X, y = mnist["data"], mnist["target"]
y = y.astype(np.uint8)
print(X.shape)
print(y.shape)

在这里插入图片描述

def plot_digit(data):
    image = data.reshape(28, 28)
    plt.imshow(image, cmap = mpl.cm.binary,
               interpolation="nearest")
    plt.axis("off")


X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:]
shuffle_index = np.random.permutation(60000) 
X_train, y_train = X_train[shuffle_index], y_train[shuffle_index]


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 = mpl.cm.binary, **options)
    plt.axis("off")

plt.figure(figsize=(9,9))
example_images = X_train[:100]
plot_digits(example_images, images_per_row=10)
plt.show()

在这里插入图片描述

y_train[:100] 

在这里插入图片描述

np.where(y_train[:100] == 5)

在这里插入图片描述

y_train[9]

在这里插入图片描述

some_digit = X_train[9]

选取1000个数据

X_train, y_train = X_train[:1000], y_train[:1000]

4.1 SVC

from sklearn.svm import SVC

svm_clf = SVC(gamma="auto", random_state=42)
svm_clf.fit(X_train, y_train)
svm_clf.predict([some_digit])

在这里插入图片描述

some_digit_scores = svm_clf.decision_function([some_digit])
some_digit_scores

在这里插入图片描述

np.argmax(some_digit_scores)

在这里插入图片描述

svm_clf.classes_

在这里插入图片描述

4.2 OneVsRestClassifier

from sklearn.multiclass import OneVsRestClassifier
ovr_clf = OneVsRestClassifier(SVC(gamma="auto", random_state=42))
ovr_clf.fit(X_train, y_train)
ovr_clf.predict([some_digit])

在这里插入图片描述

len(ovr_clf.estimators_)

在这里插入图片描述

4.3 SGDClassifier

from sklearn.linear_model import SGDClassifier

sgd_clf = SGDClassifier(max_iter=1000, tol=1e-3, random_state=42)

sgd_clf.fit(X_train, y_train)
sgd_clf.predict([some_digit])

在这里插入图片描述

sgd_clf.decision_function([some_digit])

在这里插入图片描述

交叉验证

from sklearn.model_selection import cross_val_score
cross_val_score(sgd_clf, X_train, y_train, cv=3, scoring="accuracy")

在这里插入图片描述

标椎化

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train.astype(np.float64))
cross_val_score(sgd_clf, X_train_scaled, y_train, cv=3, scoring="accuracy")

在这里插入图片描述

5 误差分析

confusion_matrix 混淆矩阵

from sklearn.model_selection import cross_val_predict
from sklearn.metrics import confusion_matrix

y_train_pred = cross_val_predict(sgd_clf, X_train_scaled, y_train, cv=3)
conf_mx = confusion_matrix(y_train, y_train_pred)
conf_mx

在这里插入图片描述

def plot_confusion_matrix(matrix):
    """If you prefer color and a colorbar"""
    fig = plt.figure(figsize=(8,8))
    ax = fig.add_subplot(111)
    cax = ax.matshow(matrix)
    fig.colorbar(cax)

plt.matshow 混淆矩阵以图像方式呈现

plt.matshow(conf_mx, cmap=plt.cm.gray)
save_fig("confusion_matrix_plot", tight_layout=False)
plt.show()

用0填充对角线 np.fill_diagonal

row_sums = conf_mx.sum(axis=1, keepdims=True)
norm_conf_mx = conf_mx / row_sums

np.fill_diagonal(norm_conf_mx, 0) # 用0填充对角线
plt.matshow(norm_conf_mx, cmap=plt.cm.gray)
save_fig("confusion_matrix_errors_plot", tight_layout=False)
plt.show()

在这里插入图片描述

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_row=5)
plt.subplot(222); plot_digits(X_ab[:25], images_per_row=5)
plt.subplot(223); plot_digits(X_ba[:25], images_per_row=5)
plt.subplot(224); plot_digits(X_bb[:25], images_per_row=5)
save_fig("error_analysis_digits_plot")
plt.show()

在这里插入图片描述

6 多标签分类

from sklearn.neighbors import KNeighborsClassifier

y_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]) # 5

在这里插入图片描述
能需要很长时间(可能需要几个小时,具体取决于您的硬件)

from sklearn.metrics import f1_score
y_train_knn_pred = cross_val_predict(knn_clf, X_train, y_multilabel, cv=3)
f1_score(y_multilabel, y_train_knn_pred, average="macro")

7 多输出分类

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

加噪声输入图片(左)
目标图片(右)

some_index = 0
plt.subplot(121); plot_digit(X_test_mod[some_index])
plt.subplot(122); plot_digit(y_test_mod[some_index])
save_fig("noisy_digit_example_plot")
plt.show()

在这里插入图片描述

训练分类器,清洁图片

knn_clf.fit(X_train_mod, y_train_mod)
clean_digit = knn_clf.predict([X_test_mod[some_index]])
plot_digit(clean_digit)
save_fig("cleaned_digit_example_plot")

在这里插入图片描述

补充

虚拟(即随机)分类

y_train_5 = (y_train == 5)

from sklearn.dummy import DummyClassifier

dmy_clf = DummyClassifier()
y_probas_dmy = cross_val_predict(dmy_clf, X_train, y_train_5, cv=3, method="predict_proba")
y_scores_dmy = y_probas_dmy[:, 1]

def plot_roc_curve(fpr, tpr, label=None):
    plt.plot(fpr, tpr, linewidth=2, label=label)
    plt.plot([0, 1], [0, 1], 'k--') # dashed diagonal
    plt.axis([0, 1, 0, 1])                                    # Not shown in the book
    plt.xlabel('False Positive Rate (Fall-Out)', fontsize=16) # Not shown
    plt.ylabel('True Positive Rate (Recall)', fontsize=16)    # Not shown
    plt.grid(True) 

from sklearn.metrics import roc_curve
fprr, tprr, thresholdsr = roc_curve(y_train_5, y_scores_dmy)
plot_roc_curve(fprr, tprr)

在这里插入图片描述

KNN classifier

from sklearn.neighbors import KNeighborsClassifier
knn_clf = KNeighborsClassifier(weights='distance', n_neighbors=4)
knn_clf.fit(X_train, y_train)

在这里插入图片描述

y_knn_pred = knn_clf.predict(X_test)

from sklearn.metrics import accuracy_score
accuracy_score(y_test, y_knn_pred)

在这里插入图片描述

from scipy.ndimage.interpolation import shift
def shift_digit(digit_array, dx, dy, new=0):
    return shift(digit_array.reshape(28, 28), [dy, dx], cval=new).reshape(784)

plot_digit(shift_digit(some_digit, 5, 1, new=100))

在这里插入图片描述

X_train_expanded = [X_train]
y_train_expanded = [y_train]
for dx, dy in ((1, 0), (-1, 0), (0, 1), (0, -1)):
    shifted_images = np.apply_along_axis(shift_digit, axis=1, arr=X_train, dx=dx, dy=dy)
    X_train_expanded.append(shifted_images)
    y_train_expanded.append(y_train)

X_train_expanded = np.concatenate(X_train_expanded)
y_train_expanded = np.concatenate(y_train_expanded)
X_train_expanded.shape, y_train_expanded.shape

在这里插入图片描述

knn_clf.fit(X_train_expanded, y_train_expanded)

在这里插入图片描述

y_knn_expanded_pred = knn_clf.predict(X_test)

accuracy_score(y_test, y_knn_expanded_pred)

在这里插入图片描述

ambiguous_digit = X_test[2589]
knn_clf.predict_proba([ambiguous_digit])

plot_digit(ambiguous_digit)

在这里插入图片描述

发布了50 篇原创文章 · 获赞 51 · 访问量 2468

猜你喜欢

转载自blog.csdn.net/hezuijiudexiaobai/article/details/104617975