2

我是 R 新手,正在尝试用更有效的方法替换附加代码块中的循环。对于上下文,这是具有多变量(3 维)目标的 k 最近邻回归的简单综合示例。

rm(list=ls())
set.seed(1)

# Fast nearest neighbor package
library(FNN)
k <- 3

# Synthetic 5d predictor and noisy 3d target data
x <- matrix(rnorm(50), ncol=5)
y <- 5*x[,1:3] + matrix(rnorm(30), ncol=3)
print(x)
print(y)

# New synthetic 5d predictor data (4 cases)
x.new <- matrix(rnorm(20), ncol=5)
print(x.new)

# Identify k-nearest neighbors
nn <- knnx.index(data=x, query=x.new, k=k)
print(nn)

目前,我通过以下循环获取 k 最近邻 (nn) 的未加权平均值:

# Unweighted k-nearest neighbor regression predictions based on y and nn
y.new <- matrix(0, ncol=ncol(y), nrow=nrow(x.new))
for(i in 1:nrow(nn))
    y.new[i,] <- colMeans(y[nn[i,],,drop=FALSE])

print(y.new)

但必须有一种简单的方法来避免在这里循环。谢谢。

4

1 回答 1

2

在这些情况下,一种选择是构建一个大矩阵并操纵索引:

y2<-array(colMeans(matrix(y[t(nn),],nrow=ncol(nn))),dim(y.new))
identical(y2,y.new) 
## [1] TRUE

在这种情况下,我的代码运行速度大约是你的两倍:

microbenchmark(
loop = for(i in 1:nrow(nn))
    y.new[i,] <- colMeans(y[nn[i,],,drop=FALSE]),
matrix=y2<-array(colMeans(matrix(y[t(nn),],nrow=ncol(nn))),dim(y.new)))
## Unit: microseconds
##    expr    min      lq  median     uq     max neval
##    loop 43.680 47.8805 49.1675 49.975 128.698   100
##  matrix 23.807 25.4330 25.9985 26.761  80.491   100

在这种情况下,循环并不是那么糟糕。一般来说,只要你在一个循环中做了很多工作(在这种情况下,对矩阵进行子集化并调用 colMeans),那么与循环的实际内容相比,每次迭代的开销就会很小。在 R 中真正需要避免循环的时候是每次迭代只做少量工作,在这种情况下,在 R 中迭代的开销将真正成为瓶颈,避免循环可以显着提高性能。

循环的优点是你在做什么非常清楚,而我的代码非常难以理解。但是,像这样进行矩阵索引操作通常会更快,有时会快很多,因为您只需对y矩阵进行一次子集化,而不是每次循环一次。

于 2013-10-10T00:37:36.920 回答