在R中将向量的每个元素与另一个向量相结合

7

我有两个向量

x <- c(2, 3, 4)
y <- rep(0, 5)

我希望得到如下输出:
> z
2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0

我该如何创建z?我尝试使用pastec,但是似乎都没有效果。我唯一能想到的就是使用for(),但它非常慢。我已经在谷歌上搜索过,并且确定解决方案存在,只是我没有使用正确的关键词。
更新: 为了进行基准测试:
使用Nicola的解决方案:
 > system.time(
+ precipitation <- `[<-`(numeric(length(x)*(length(y)+1)),seq(1,by=length(y)+1,length.out=length(x)),x)
+ )
user  system elapsed 
0.419   0.407   0.827 

这太快了!我必须说!有人能解释一下吗?我的for()R中总是错误的,即使它完成了,也需要至少一天。

其他建议:

 > length(prate)
[1] 4914594
> length(empty)
[1] 207
> system.time(
+ precipitation <- unlist(sapply(prate, FUN = function(prate) c(prate,empty), simplify=FALSE))
+ )
user  system elapsed 
16.470   3.859  28.904 

我必须杀死。
len <- length(prate)
precip2 <- c(rbind(prate, matrix(rep(empty, len), ncol = len)))

15分钟后。

虽然不如@nicola的方法快,但另一个选择是rep(x, each=length(y)+1)*c(1,y) - akrun
y 全为零时,我进行了编辑以加快速度。 - nicola
5个回答

5
您可以尝试这个。
unlist(sapply(x, FUN = function(x) c(x,y), simplify=FALSE))
 [1] 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 0

从@docendodiscimus的角度来看,或者更简单一些。
unlist(lapply(x, FUN = function(x) c(x,y)))

1
你可以使用 lapply,这样就不需要指定 simplify = FALSE。 - talat
我还没有尝试过其他建议,但这个非常快(大约需要30秒,而我的循环至少需要一天)。 - cdd
@cddesjardins 如果您也测试其他答案的速度,那将会很有趣。 - David Arenburg
你可以在调用时添加y,这样它就不依赖于y作为第二个向量的名称,结果如下:unlist(lapply(x, function(x, y) c(x,y), y)) - leo

5

出现了一些原因,这似乎更快:

 unlist(t(matrix(c(as.list(x),rep(list(y),length(x))),ncol=2)))

以上解决方案是通用的,因为xy都可以有任何值。在OP的情况下,y只由0组成,所以这是最快的:

 `[<-`(numeric(length(x)*(length(y)+1)),seq(1,by=length(y)+1,length.out=length(x)),x)
 #[1] 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 0

编辑

我意识到我的描述过于隐晦,而且我写的代码即使只有一行也不容易理解。我将详细解释第二种解决方案的工作原理。

首先,你会注意到最终的向量将包含x中的值以及y中的零重复length(x)次。因此,总长度为length(x) + length(x)*length(y)length(x)*(length(y)+1)。因此,我们创建一个长度为所需长度的零向量:

  res<-numeric(length(x)*(length(y)+1))

现在我们需要将x的值放入res中。 我们注意到,x的第一个值占据res中的第一个值;第二个值将位于第一个值之后的length(y)+1处,依此类推,直到填充完所有的length(x)值。我们可以创建一个索引向量来存放x的值:
  indices<-seq.int(1,by=length(y)+1,length.out=length(x))

然后我们进行替换:

  res[indices]<-x

我的这一行只是前面三行的简化。希望这能稍微澄清一下。


1
你的解决方案是目前最快的。我认为 t 可能会降低速度,但实际上并没有。 - akrun
1
是的,有趣的解决方案。 - David Arenburg
1
非常棒的解决方案。您可以使用“整数”而不是“数字”,以使其更快。 - cryo111
1
另外,使用 seq.int 而不是 seq 似乎更快。 ;) - cryo111
1
Nicola的解决方案基本上是x=1:1e5;y=rep(0,40);tmp=numeric(length(x)*(length(y)+1));tmp[seq(1,by=length(y)+1,length.out=length(x))]=x;的简写。比较:<code>all.equal([<-(numeric(length(x)*(length(y)+1)),seq(1,by=length(y)+1,length.out=length(x)),x),tmp)</code>。 - cryo111
显示剩余2条评论

2
您可以尝试以下向量化方法:
len <- length(x)
c(rbind(x, matrix(rep(y, len), ncol = len)))
## [1] 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 0

一种更紧凑但可能较慢的选项(由@akrun提供)是:
c(rbind(x, replicate(len, y)))
## [1] 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 0

尝试在一个长度为1e6的“x”向量和长度为100的“y”上进行一些基准测试。使用dim<-更快一些,@Mamoun Benghezal的解决方案最先出现,而“复制”方案最慢,尽管在1比2.9的比例上。 - akrun
@akrun 有趣。不过有点奇怪。 - David Arenburg

1
你可以尝试:

 c(sapply(x, 'c', y))
 #[1] 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 

或者使用gusb和paste的疯狂解决方案。
library(functional)
p = Curry(paste0, collapse='')

as.numeric(strsplit(p(gsub('(.*)$', paste0('\\1',p(y)),x)),'')[[1]])
#[1] 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 0

1
这是另一种方式:
options(scipen=100)
as.numeric(unlist(strsplit(as.character(x * 10^5), "")))

还有一些基准测试:

microbenchmark({as.numeric(unlist(strsplit(as.character(x*10^5), "")))}, {unlist(t(matrix(c(as.list(x),rep(list(y),length(x))),ncol=2)))}, {unlist(sapply(x, FUN = function(x) c(x,y), simplify=FALSE))}, times=100000)
Unit: microseconds
                                                                        expr
            {     as.numeric(unlist(strsplit(as.character(x * 10^5), ""))) }
 {     unlist(t(matrix(c(as.list(x), rep(list(y), length(x))), ncol = 2))) }
      {     unlist(sapply(x, FUN = function(x) c(x, y), simplify = FALSE)) }
   min     lq     mean median     uq       max  neval
 9.286 10.644 12.15242 11.678 12.286  1650.133 100000
 9.485 11.164 13.25424 12.288 13.067  1887.761 100000
 5.607  7.429  9.21015  8.147  8.784 30457.994 100000

这里还有一个想法(但似乎比较慢):

r = rle(1)
r$lengths = rep(c(1,5), length(x))
r$values =  as.vector(rbind(x, 0))
inverse.rle(r)

根据 OP 帖子中的 x,我得到了 as.numeric(unlist(strsplit(as.character(x * 10^5), ""))) # [1] 2 NA NA 0 5 3 NA NA 0 5 4 NA NA 0 5,但这不是预期结果。 - akrun
有趣的是,我得到了正确的结果:as.numeric(unlist(strsplit(as.character(x * 10^5), ""))) [1] 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 0 - nsheff
@akrun 哦,是的 - 关闭科学计数法:options(scipen=100) - nsheff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接