You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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")

额外改进建议

  1. 优化距离计算效率:philentropy::distance在处理大矩阵时效率不算最高,对于常用距离(比如欧氏、曼哈顿),可以手动实现或者用R内置的dist函数,速度会快很多。比如手动计算欧氏距离:
# 单个测试样本到训练集的欧氏距离(向量化实现,比循环快)
dist_vec <- sqrt(colSums((t(train_features) - test_features[i, ])^2))
  1. 适配高维数据特性:你参考的论文聚焦高维空间距离度量的变化,建议你:
    • 尝试多种距离(曼哈顿、余弦、切比雪夫等),对比它们在30维数据集上的表现
    • 可以尝试PCA降维后再做KNN,观察距离度量效果的变化,验证论文里的结论
  2. 加入交叉验证:不要只用单一的训练/测试划分,用K折交叉验证评估不同距离度量的稳定性,结果会更可靠
  3. 替换循环提升速度:如果样本量很大,循环会很慢,可以用apply族函数或者向量化操作替代循环

参考资料

  • R官方文档中dist函数的说明:可以学习内置距离计算的高效实现方式
  • 《An Introduction to Statistical Learning》中KNN章节:详细讲解KNN的原理和工程实现细节
  • 你提到的《On the Surprising Behavior of Distance Metrics in High Dimensional Space》:重点关注高维空间中不同距离的区分度退化问题,尤其是欧氏距离的表现

内容的提问来源于stack exchange,提问作者jeza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:12:03