knn算法适用于较小的数据集,在处理大数据集时由于knn算法需要计算测试样本与所有训练样本之间的距离。所以计算复杂度高,预测速度慢。
为了缓解这个问题, 可以先把 10,000 条训练数据聚为 50 个簇, 每簇约 200 个样本 (聚类问题), 并获得这些簇中心点. 进行比对的时候, 先确定与哪个簇中心最近, 然后再在这个簇中心找邻居. 这样就可以把 10,000 次对比降为约 50 + 200 次.
使用鸢尾花数据集做示例,鸢尾花有150多个样本,先使用kmeans进行聚类,把训练集聚为三个簇,然后再为每一簇构建一个knn分类器,把150 次对比降为约 3+50次.
使用kmeans和knn进行鸢尾花分类
首先,导入所需的库:
import numpy as np
import operator
from sklearn.datasets import load_iris
from sklearn.preprocessing import standardscaler
from sklearn.model_selection import train_test_split
from sklearn.cluster import kmeans
from sklearn.metrics import accuracy_score
接下来,定义一个函数knnclassify
来执行knn分类。这个函数计算测试数据与训练数据之间的距离,然后根据距离排序,并选择距离最小的k个样本点。然后,它确定k个样本点所在类别的出现频率,并返回最高频率的类别作为预测分类。
def knnclassify(inputx, data, labels, k):
# 1. 计算测试数据与各训练数据之间的距离。
datasize = data.shape[0]
x = np.tile(inputx, (datasize, 1)) - data
xpositive = x ** 2
xdistances = xpositive.sum(axis=1)
distances = np.sqrt(xdistances)
# 2. 按照距离的大小进行排序。
sortdisindex = distances.argsort()
# 3. 选择其中距离最小的k个样本点。4. 确定k个样本点所在类别的出现频率。
classcount = {} # 创建字典:label为键,频数为值
for i in range(k):
getlabel = labels[sortdisindex[i]]
classcount[getlabel] = classcount.get(getlabel, 0) + 1
# 5. 返回k个样本点中出现频率最高的类别作为最终的预测分类。
sortclass = sorted(classcount.items(), key=operator.itemgetter(1), reverse=true)
return sortclass[0][0]
加载鸢尾花数据集,并对特征进行归一化:
data = load_iris()
x = data.data[:, :3] # 选择前三个特征
y = data.target
scaler = standardscaler()
x_scaled = scaler.fit_transform(x)
将数据集划分为训练集和测试集:
x_train, x_test, y_train, y_test = train_test_split(x_scaled, y, test_size=0.2, random_state=42)
使用kmeans聚类算法将训练集进行聚类,并获取聚类中心(选取三个聚类中心):
kmeans = kmeans(n_clusters=3)
kmeans.fit(x_train)
cluster_centers = kmeans.cluster_centers_
为每个聚类中心创建一个自定义的knn分类器,并将其存储在classifiers
列表中:
classifiers = []
for cluster_idx in range(kmeans.n_clusters):
cluster_samples = x_train[kmeans.predict(x_train) == cluster_idx]
cluster_labels = y_train[kmeans.predict(x_train) == cluster_idx]
classifiers.append((cluster_samples, cluster_labels))
使用分类器对测试集进行预测:
y_pred = []
for sample in x_test:
distances = [np.linalg.norm(sample - center) for center in cluster_centers]
closest_cluster_idx = np.argmin(distances)
cluster_samples, cluster_labels = classifiers[closest_cluster_idx]
y_pred.append(knnclassify(sample, cluster_samples, cluster_labels, k=3))
最后,计算分类的准确率并进行输出:
accuracy = accuracy_score(y_test, y_pred)
print(f"accuracy: {accuracy}")
虽然这种方式速度更快,但是会降低一定的精度。
运行结果
下面是不进行聚类直接使用knn进行分类的结果
发表评论