【问题标题】:How to choose the "best" samples for training KNN classifier?如何选择训练 KNN 分类器的“最佳”样本?
【发布时间】:2021-03-12 02:27:23
【问题描述】:

我想在限制训练样本数量的同时构建一个 KNN 分类器。 例如,我有一个总共有 60K 训练样本的 MNIST 数据集,我正在寻找一种方法来选择该数据集的大小为n 的子集,以提供最佳分类器(就准确性而言)。 这相当于寻找最能“代表”数据(或数据分布)的n 样本。
下面是一些示例代码来澄清这个问题:

from sklearn.neighbors import KNeighborsClassifier
from keras.datasets import mnist
from sklearn.model_selection import train_test_split
import numpy as np
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(x_train.shape[0], -1)
x_test = x_test.reshape(x_test.shape[0], -1)
n_digits = 10
ims_per_class = list(range(1, 11)) + [12, 15, 20]
scores = []
for i in ims_per_class :
    x_train_k, _, y_train_k, _ = train_test_split(x_train, y_train, train_size=n_digits * i, stratify=y_train, random_state=42)
    neigh = KNeighborsClassifier(n_neighbors=1)
    neigh.fit(x_train_k, y_train_k)
    scores.append(neigh.score(x_test, y_test))

结果如预期所示,在随机选择样本时,随着训练样本数量的增加,模型变得更好。

但是,如果我选择在每个类由单个样本(即平均像素值)表示时训练模型,我会得到更好的结果:

x_train_mean, y_train_mean = zip(*[(x_train[y_train == i].mean(axis=0), i) for i in range(n_digits)])
x_train_mean = np.stack(x_train_mean, axis=0)
neigh.fit(x_train_mean, y_train_mean)
print(neigh.score(x_test, y_test))
0.8203

n=#classes 时,按类别平均样本比随机抽取样本产生更好的结果,我想知道 n>#classes 时如何扩展选择过程?

  • 目前,问题的范围是K=1 的情况(KNN 图中的邻居数),但是,也欢迎对不同 K 值进行良好泛化的解决方案!

【问题讨论】:

  • 这里的n 不清楚你的意思。在循环中,您使用n 来表示每个类的图像数量。 n = 11, 12, 15, 20 已经是 >#classes(假设 MNIST 有 10 个类)。那么你到底是什么意思呢?
  • n 是训练样本的总数,如果我为每个班级拍摄一张图片,最好的方法是取班级图片的平均值(即在n=10 选择一个每个类的随机图像将产生acc~=0.38,而取平均值则产生acc=0.82)。我已经编辑了代码 sn-p 以使其更清晰。
  • 我不明白为什么有人要选择最好的 N 张图片来训练他们的模型。如果你在测试中挑选你的数据集,它们可能会出现巨大的性能错误。我错过了什么吗?
  • @itamarkanter 要很好地代表您的图像分布,只需确保在您的 y 标签上对数据进行分层。因此,您将拥有一个均匀分布在所有不同类别之间的训练集。就是这样。
  • @ombk 我想选择最好的 n 以减小 KNN 模型的大小。请注意,在我提供的示例中,我使用分层数据训练模型。但是您可以看到,当随机抽取 10 个分层数据点(即每个类别的单个图像)时,结果比获取每个类别的平均像素强度的 10 个伪图像要差得多。我想知道是否可以找到一种类似的方法,它比随机选择图像(在 y 上分层)更好,以防我可以为每个类选择多个样本

标签: python machine-learning knn


【解决方案1】:

我发现了多种方法建议如何选择“最佳”样本,其中包括:

但我发现,采用基于聚类的更简单方法会产生不错的结果。 这个想法很简单,只需将每个类聚类成 n 个“代表性”聚类(k-means,但 GMM 也可以),并使用这些聚类来训练 KNN 模型。 您可以在以下代码 sn-p 和图形中看到通过这种方法实现的增益:

from sklearn import datasets, svm, metrics
from sklearn.neighbors import KNeighborsClassifier
from keras.datasets import mnist
from sklearn.model_selection import train_test_split
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(x_train.shape[0], -1)
x_test = x_test.reshape(x_test.shape[0], -1)

n_digits = 10
ks = list(range(1, 11)) + [12, 15, 20]
scores = []
scores_kmeans = []
for k in ks:
    # naive
    x_train_k, _, y_train_k, _ = train_test_split(x_train, y_train, train_size=n_digits * k, stratify=y_train, random_state=42)
    neigh = KNeighborsClassifier(n_neighbors=1)
    neigh.fit(x_train_k, y_train_k)
    scores.append(neigh.score(x_test, y_test))
    # k-means
    x_train_kmeans = []
    y_train_kmeans = []
    for i in range(n_digits):
        x_train_kmeans.append(KMeans(n_clusters=k, random_state=0, n_init=10).fit(x_train[y_train == i]).cluster_centers_)
        y_train_kmeans.extend([i] * k)
    x_train_kmeans = np.concatenate(x_train_kmeans)
    neigh = KNeighborsClassifier(n_neighbors=1)
    neigh.fit(x_train_kmeans, y_train_kmeans)
    scores_kmeans.append(neigh.score(x_test, y_test))

plt.plot(ks, scores, label='naive')
plt.plot(ks, scores_kmeans, label='k-means')
plt.ylabel('acc')
plt.xlabel('images per class')
plt.legend()

【讨论】:

    猜你喜欢
    • 2015-06-17
    • 2019-11-30
    • 1970-01-01
    • 2012-04-18
    • 1970-01-01
    • 2018-01-01
    • 2014-05-28
    • 2020-09-20
    • 2021-03-06
    相关资源
    最近更新 更多