我陷入了R中的一个难题,我无法解决它。问题是这样的。
x和y是两个向量,如下所示:
x<- c(1,2,3,4,5)
y<- c(12,4,2,5,7,18,9,10)
我想以下列方式创建一个新的向量p,其中length(p)= length(x):
现在我们必须以下列方式更新p:
由于p中的下一个值是2和4,我们必须重复我们在最后两个步骤中所做的操作。总之,在计算x和y之间的最小距离时,对于x的每个id,我们必须得到之前未出现的y的id。因此p的所有元素必须是唯一的。
任何答案都将不胜感激。
我试过这样的事情,虽然不是一个完整的解决方案:
minID <- function(x,y) {return(which(abs(x-y)==min(abs(x-y))))};
p1 <- sapply(x,minID,y=y);
#Calculates the list of all minimum elements -no where close to actual solution :(
我的x和y超过100万,因此循环会非常慢。我正在寻找更快的解决方案。
答案 0 :(得分:9)
这可以通过y
元素上的二元搜索树有效实现,删除元素,因为它们匹配并添加到p
。我使用C ++中的stl使用set
实现了这一点,使用Rcpp将代码放入R:
library(Rcpp)
getVals = cppFunction(
'NumericVector getVals(NumericVector x, NumericVector y) {
NumericVector p(x.size());
std::vector<std::pair<double, int> > init;
for (int j=0; j < y.size(); ++j) {
init.push_back(std::pair<double, int>(y[j], j));
}
std::set<std::pair<double, int> > s(init.begin(), init.end());
for (int i=0; i < x.size(); ++i) {
std::set<std::pair<double, int> >::iterator p1, p2, selected;
p1 = s.lower_bound(std::pair<double, int>(x[i], 0));
p2 = p1;
--p2;
if (p1 == s.end()) {
selected = p2;
} else if (p2 == s.begin()) {
selected = p1;
} else if (fabs(x[i] - p1->first) < fabs(x[i] - p2->first)) {
selected = p1;
} else {
selected = p2;
}
p[i] = selected->second+1; // 1-indexed
s.erase(selected);
}
return p;
}')
这是与已发布的纯R解决方案的运行时比较 - 二进制搜索树解决方案更快,并且只需几秒钟即可启用长度为100万的向量的解决方案:
# Pure-R posted solution
getVals2 = function(x, y) {
n <- length(x)
p <- rep(NA, n)
for(i in 1:n) {
id <- which.min(abs(y - x[i]))
y[id] <- Inf
p[i] <- id
}
return(p)
}
# Test with medium-sized vectors
set.seed(144)
x = rnorm(10000)
y = rnorm(20000)
system.time(res1 <- getVals(x, y))
# user system elapsed
# 0.008 0.000 0.008
system.time(res2 <- getVals2(x, y))
# user system elapsed
# 1.284 2.919 4.211
all.equal(res1, res2)
# [1] TRUE
# Test with large vectors
set.seed(144)
x = rnorm(1000000)
y = rnorm(2000000)
system.time(res3 <- getVals(x, y))
# user system elapsed
# 4.402 0.097 4.467
加速的原因是因为这种方法渐近更快 - 如果x
的大小为n
且y
大小为m
,那么二进制搜索树方法在O((n+m)log(m))
时间 - O(m log(m))
运行以构建BST,O(n log(m))
计算p
- 而which.min
方法在O(nm)
运行时间。
答案 1 :(得分:3)
n <- length(x)
p <- rep(NA, n)
for(i in 1:n) {
id <- which.min(abs(y - x[i]))
y[id] <- Inf
p[i] <- id
}
答案 2 :(得分:0)
我尝试在R中开发代码,并且在for循环中获得了大约20倍的改进。这段代码如下:
Generalized.getMinId <- function(a,b)
{
sapply(a, FUN = function(x) which.min(abs(x-b)))
}
Generalized.getAbsDiff <- function(a,b)
{
lapply(a, FUN = function(x) abs(x-b))
}
min_id = Generalized.getMinId(tlist,clist);
dup = which(duplicated(min_id));
while(length(dup) > 0)
{
absdiff = Generalized.getAbsDiff(tlist[dup],clist);
infind = lapply(dup, function(x,y)
{l <- head(y,x-1); l[l>0]}, y = min_id);
absdiff = Map(`[<-`, absdiff, infind, Inf);
dupind = sapply(absdiff, which.min);
min_id[dup] = dupind;
dup = which(duplicated(min_id));
}
如果有人可以对这段代码进行改进,那就太棒了。