基于R实现不同距离度量的KNN:自写代码正确性验证问询
你的KNN代码问题分析与改进方案
嘿,咱们先拆解下你的代码里的几个关键问题——这些不仅会影响结果正确性,还会拖慢运行效率,正好也能帮你对齐目标论文的实验需求:
核心问题点
- 距离计算逻辑既错又低效:你在循环里每次都对整个
xmat计算全量距离矩阵,这不仅重复做了大量无用计算,而且没提取当前样本对应的行距离。比如处理第i个样本时,应该取距离矩阵的第i行,而不是拿着整个矩阵去排序。 - 没区分训练集和测试集:你已经划分了
wdbc_train和wdbc_test,但当前代码是在同一个矩阵里做“留一法”近邻查找,实际应该是用训练样本的特征,计算每个测试样本到所有训练样本的距离,再找近邻。 - 缺少分类准确率统计:你说目标是统计标签匹配正确数,但当前函数只返回了近邻索引,完全没结合标签做计算。
- 边界场景处理不足:比如测试样本和训练样本维度不一致时没有校验,而且如果是训练-测试场景,不需要排除自身(因为测试样本不在训练集里),你的
order(ddist)[2:(k+1)]是留一法的逻辑,放到训练-测试里就错了。
改进后的代码示例
结合你的需求(用训练集预测测试集,统计K=1时的分类准确率,支持不同距离度量),我重写了KNN函数,适配你的数据集情况:
library(philentropy) # 改进的KNN分类函数:支持训练集-测试集分离,计算分类准确率 knn_classify <- function(train_features, train_labels, test_features, k, method = "euclidean") { # 校验输入维度一致性 if(ncol(train_features) != ncol(test_features)) { stop("训练集和测试集的特征维度必须一致!") } if(k > nrow(train_features)) { stop("k不能大于训练集样本数量!") } n_test <- nrow(test_features) predictions <- character(n_test) for(i in 1:n_test) { # 构造临时矩阵:训练样本 + 当前测试样本,取最后一行得到测试样本到所有训练样本的距离 temp_mat <- rbind(train_features, test_features[i, , drop = FALSE]) dist_mat <- distance(temp_mat, method = method) dist_vec <- dist_mat[nrow(dist_mat), 1:(nrow(dist_mat)-1)] # 找到距离最小的k个训练样本索引,K=1时直接取第一个 nearest_idx <- order(dist_vec)[1:k] # 投票获取预测标签(K=1时直接取对应标签) nearest_labels <- train_labels[nearest_idx] predictions[i] <- names(sort(table(nearest_labels), decreasing = TRUE)[1]) } # 计算准确率(如果传入测试标签的话) accuracy <- NULL if(!missing(test_labels)) { if(length(predictions) != length(test_labels)) { stop("预测结果和测试标签长度不一致!") } accuracy <- mean(predictions == test_labels) } return(list(predictions = predictions, accuracy = accuracy)) } # 假设原始wdbc数据集的第2列是诊断标签(diagnosis),提取训练和测试标签 wdbc_train_labels <- wdbc[1:469, 2] wdbc_test_labels <- wdbc[470:569, 2] # 测试欧氏距离K=1的分类效果 result_euclidean <- knn_classify(wdbc_train, wdbc_train_labels, wdbc_test, k=1, method="euclidean") cat("欧氏距离K=1的分类准确率:", result_euclidean$accuracy, "\n")
额外改进建议
- 优化距离计算效率:
philentropy::distance在处理大矩阵时效率不算最高,对于常用距离(比如欧氏、曼哈顿),可以手动实现或者用R内置的dist函数,速度会快很多。比如手动计算欧氏距离:
# 单个测试样本到训练集的欧氏距离(向量化实现,比循环快) dist_vec <- sqrt(colSums((t(train_features) - test_features[i, ])^2))
- 适配高维数据特性:你参考的论文聚焦高维空间距离度量的变化,建议你:
- 尝试多种距离(曼哈顿、余弦、切比雪夫等),对比它们在30维数据集上的表现
- 可以尝试PCA降维后再做KNN,观察距离度量效果的变化,验证论文里的结论
- 加入交叉验证:不要只用单一的训练/测试划分,用K折交叉验证评估不同距离度量的稳定性,结果会更可靠
- 替换循环提升速度:如果样本量很大,循环会很慢,可以用
apply族函数或者向量化操作替代循环
参考资料
- R官方文档中
dist函数的说明:可以学习内置距离计算的高效实现方式 - 《An Introduction to Statistical Learning》中KNN章节:详细讲解KNN的原理和工程实现细节
- 你提到的《On the Surprising Behavior of Distance Metrics in High Dimensional Space》:重点关注高维空间中不同距离的区分度退化问题,尤其是欧氏距离的表现
内容的提问来源于stack exchange,提问作者jeza
相关产品推荐
相关产品推荐

