高效的knn算法

Posted

技术标签:

【中文标题】高效的knn算法【英文标题】:Efficient knn algorithm 【发布时间】:2016-08-02 02:49:29 【问题描述】:

我正在尝试实现在 R 中对一维向量进行操作的 knn 算法,但它与标准向量略有不同,因为它在平局的情况下采用较小的元素(所以距离是只是属性之间差异的绝对值)。更准确地说,我试图找到最接近给定数字的 k 个数字,如果有平局,我希望选择较小的数字。

听起来很简单,但我的算法需要几秒钟才能完成,而类包 (knn) 中的算法会立即输出答案(尽管在平局或随机元素的情况下它需要所有元素)......我的是以下:

    我对一个训练样本进行抽样,并逐步对其进行排序。 取元素(数字) 2.5.并在训练样本中搜索它变得小于某个数字的第一个位置。 我从训练样本中提取 2k+1 个数字——k 在 2.5 中找到的数字的左侧,k 在右侧(如果这样的数字少于 k,我会尽可能多地提取)。 最后,我计算所选元素与我在 2 中所取元素的距离,并将它们与相应元素一起递增排序(以便元素及其距离递增排序) 然后我从 4 中创建的列表中取出 k 个第一个元素。(因此没有两个元素具有相同的距离)

但是男孩,完成需要 6 或 7 秒...你有什么改进的想法吗? (这不是 R 特定的问题,只是碰巧我在 R 中做的)。

编辑。代码:

dec <- function(u, x, k) 
## u is the training sample sorted increasingly
## x is an object for classification
## k is a knn parameter
knn <- list()
i <- 1
div <- 0
for (j in u) 
    if (x < j) 
        div <- 0
        break

    i <- i+1

if (div == 0) 
    distances <- array(0,dim=c(2,k))
    z <- 1
    for (j in 1:k) 
        distances[1,z] <- u[10000-j]
        distances[2,z] <- abs(u[10000-j]-x)
    
 else 
    end1 <- div+k
    end2 <- div-k
    if (div<k) 
        distances <- array(0,dim=c(2,(div+k)))
        a <- 1
        for (j in u[1:end1]) 
            distances[1,a] <- j
            distances[2,a] <- abs(j-x)
            a <- a+1
        
     else if (10000-div<k) 
        distances <- array(0,dim=c(2,(1000-div+k)))
        a <- 1
        for (j in u[end2:10000]) 
            distances[1,a] <- j
            distances[2,a] <- abs(j-x)
            a <- a+1
        
     else 
        a <- 1
        distances <- array(0,dim=c(2,(2*k+1)))
        for (j in u[end1:end2]) 
            distances[1,a] <- j
            distances[2,a] <- abs(j-x)
            a <- a+1
        
    
    distances <- t(distances)
    distances <- distances[ order( distances[,2], distances[,1]), ]
    distances <- t(distances)

for (i in 1:k)     
    if (i>1 && distances[1,i-1] != distances[1,i])
        knn[i] <- distances[1,i]

 ## and sth later...

【问题讨论】:

你的样本有单一属性吗? @svs:确实,k-means 和 k-nearest-neighbors 是两个不同的东西。 @Yves 是的,我的样本只有一个属性。 是的,你是对的。我不知道我在想什么。你能提供你的代码吗?你的算法似乎没问题。应该是实现的问题。 当然。给我一点时间。 【参考方案1】:

一维中的 kNN 很简单。

逐渐对值进行排序。要执行查询,请通过二分搜索在排序序列中定位值。然后通过在任一侧(更小或更大)k 次步进到最近的值来找到 k 个最接近的值。

【讨论】:

这或多或少是OP所说的他在做什么? @svs。是的。查看 2k+1 个样本并对其进行排序是不必要的。一个隐式的合并过程就可以了。但是看到 OP 测量的性能,他实际上实现了一些不同的东西。 哦,对了,我想二分法搜索会是正确的。 @Jules:我没有仔细看,因为我不是 R 精通,但我不会对你无意识地构建大型临时数组感到惊讶。

以上是关于高效的knn算法的主要内容,如果未能解决你的问题,请参考以下文章

knn算法如何选择一个最佳k值

简单数字识别(knn算法)

深入浅出KNN算法 介绍篇

KNN算法

2. KNN和KdTree算法实现

kNN(k-NearestNeighbor)算法