我希望能够在R中从3到50制作一个向量,看起来像这样:
3 4 4 5 6 6 7 8 8 .. 50 50
我想使用一个for循环内嵌另一个for循环,但它并没有产生我想要的效果。
f <- c()
for (i in 3:50) {
for(j in 1:2) {
f = c(f, i)
}
}
这是什么问题?
另一个选择是使用内嵌的rep
:
rep(3:50, rep(1:2, 24))
这将导致:
[1] 3 4 4 5 6 6 7 8 8 9 10 10 11 12 12 13 14 14 15 16 16 17 18 18 19 20 20
[28] 21 22 22 23 24 24 25 26 26 27 28 28 29 30 30 31 32 32 33 34 34 35 36 36 37 38 38
[55] 39 40 40 41 42 42 43 44 44 45 46 46 47 48 48 49 50 50
这利用了 rep
函数的 times
参数也可以是一个整数向量,其长度等于 x 参数的长度。
您可以将其推广到:
s <- 3
e <- 50
v <- 1:2
rep(s:e, rep(v, (e-s+1)/2))
甚至可以使用rep
和rep_len
的组合选项:
v <- 3:50
rep(v, rep_len(1:2, length(v)))
as.vector(sapply(0:23 * 2 + 2, function(x) x + c(1, 2, 2)))
# [1] 3 4 4 5 6 6 7 8 8 9 10 10 11 12 12 13 14 14 15 16 16 17 18 18 19 20 20 21 22 22 23 24 24 25 26 26
# [37] 27 28 28 29 30 30 31 32 32 33 34 34 35 36 36 37 38 38 39 40 40 41 42 42 43 44 44 45 46 46 47 48 48 49 50 50
基准测试
以下是所有当前答案的性能比较结果。结果显示cumsum(rep(c(1, 1, 0), 24)) + 2L
(m8
)最快,而rep(3:50, rep(1:2, 24))
(m1
) 与 m8
几乎一样快。
library(microbenchmark)
library(ggplot2)
perf <- microbenchmark(
m1 = {rep(3:50, rep(1:2, 24))},
m2 = {rep(3:50, each = 2)[c(TRUE, FALSE, TRUE, TRUE)]},
m3 = {v <- 3:50; sort(c(v,v[v %% 2 == 0]))},
m4 = {as.vector(t(cbind(seq(3,49,2),seq(4,50,2),seq(4,50,2))))},
m5 = {as.vector(sapply(0:23 * 2 + 2, function(x) x + c(1, 2, 2)))},
m6 = {sort(c(3:50, seq(4, 50, 2)))},
m7 = {rep(seq(3, 50, 2), each=3) + c(0, 1, 1)},
m8 = {cumsum(rep(c(1, 1, 0), 24)) + 2L},
times = 10000L
)
perf
# Unit: nanoseconds
# expr min lq mean median uq max neval
# m1 514 1028 1344.980 1029 1542 190200 10000
# m2 1542 2570 3083.716 3084 3085 191229 10000
# m3 26217 30329 35593.596 31871 34442 5843267 10000
# m4 43180 48321 56988.386 50891 55518 6626173 10000
# m5 30843 35984 42077.543 37526 40611 6557289 10000
# m6 40611 44209 50092.131 46779 50891 446714 10000
# m7 13879 16449 19314.547 17478 19020 6309001 10000
# m8 0 1028 1256.715 1028 1542 71454 10000
seq
的解决方案比仅使用 rep
的解决方案要慢一些。此外,添加 sort
也可能会增加一些时间。但是,时间差异只有纳秒级别。它们都是好的答案。 - wwwm6
中删除了sort
后,它的平均时间约为15k。但仍然远远不及m1
或m2
。因此,rep
必须比seq
快得多。 - kangaroo_cliffsort
所花费的时间并不感到惊讶。如果我从我的解决方案中删除 sort
,那么它将接近顶级表现者,但是 sort
不能被去除。 - MKRmicrobenchmark
的评估。R有时候可以出奇地快。 - John Colemanrep
函数,结合可能使用的逻辑索引回收...[c(TRUE, FALSE, TRUE, TRUE)]
。rep(3:50, each = 2)[c(TRUE, FALSE, TRUE, TRUE)]
## [1] 3 4 4 5 6 6 7 8 8 9 10 10 11 12 12 13 14 14 15 16 16 17 18 18 19
## [26] 20 20 21 22 22 23 24 24 25 26 26 27 28 28 29 30 30 31 32 32 33 34 34 35 36
## [51] 36 37 38 38 39 40 40 41 42 42 43 44 44 45 46 46 47 48 48 49 50 50
TRUE
/FALSE
)作为索引(在[
]
内部),则TRUE
将导致选择相应的元素,FALSE
将导致省略。如果逻辑索引向量(c(TRUE, FALSE, TRUE, TRUE)
)比索引向量(rep(3:50, each = 2)
在您的情况下)短,则索引向量被重复使用。
另外需要注意的是:每当您使用R代码时
x = c(x, something)
x = rbind(x, something)
如果你使用类似于C语言的编程风格来写R代码,那么你会让你的代码变得不必要复杂,并且在处理大型数据集(比如200MB以上)时可能会导致性能低下和内存不足的问题。R被设计用来避免对数据结构进行底层操作。
想了解更多关于贪婪行为及其惩罚的信息,请阅读《R地狱》中的第二章:Growing Objects。
even
值(基于OP的意图)的向量,然后将两个向量简单地连接起来。示例如下:v <- 3:50
sort(c(v,v[v %% 2 == 0]))
# [1] 3 4 4 5 6 6 7 8 8 9 10 10 11 12 12 13 14 14 15 16 16
# 17 18 18 19 20 20 21 22 22 23 24 24 25 26 26 27 28 28
#[40] 29 30 30 31 32 32 33 34 34 35 36 36 37 38 38 39 40 40 41 42 42
# 43 44 44 45 46 46 47 48 48 49 50 50
microbenchmark
显示它比我的解决方案更快。 - John Coleman这里有一个不使用循环的一行解决方案:
> as.vector(t(cbind(seq(3,49,2),seq(4,50,2),seq(4,50,2))))
[1] 3 4 4 5 6 6 7 8 8 9 10 10 11 12 12 13 14 14 15 16 16 17
[23] 18 18 19 20 20 21 22 22 23 24 24 25 26 26 27 28 28 29 30 30 31 32
[45] 32 33 34 34 35 36 36 37 38 38 39 40 40 41 42 42 43 44 44 45 46 46
[67] 47 48 48 49 50 50
f <- vector("numeric",74)
),以便您不必每次增加1个元素时都扩展它。您目前正在使用的 f <- c(f,i)
习语在每个阶段都复制所有旧元素,只创建一个仅比旧向量长1个元素的新向量。虽然这里的元素太少以至于没有什么区别,但如果您尝试以这种方式创建大型向量,则性能可能会非常差。rep(seq(3, 50, 2), each=3) + c(0, 1, 1)
[1] 3 4 4 5 6 6 7 8 8 9 10 10 11 12 12 13 14 14 15 16
[21] 16 17 18 18 19 20 20 21 22 22 23 24 24 25 26 26 27 28 28 29
[41] 30 30 31 32 32 33 34 34 35 36 36 37 38 38 39 40 40 41 42 42
[61] 43 44 44 45 46 46 47 48 48 49 50 50
这里是使用cumsum
的第二种方法
cumsum(rep(c(1, 1, 0), 24)) + 2L
这应该很快。
sort(c(3:50, seq(4, 50, 2)))
另一个想法,虽然速度不如最快的解决方案:
mat <- matrix(3:50,nrow=2)
c(rbind(mat,mat[2,]))
# [1] 3 4 4 5 6 6 7 8 8 9 10 10 11 12 12 13 14 14 15 16 16 17 18 18 19 20 20 21 22 22
# [31] 23 24 24 25 26 26 27 28 28 29 30 30 31 32 32 33 34 34 35 36 36 37 38 38 39 40 40 41 42 42
# [61] 43 44 44 45 46 46 47 48 48 49 50 50
for(j in 1:2)
,无论i
是奇数(那么j
应该为1)还是偶数(那么j
应该循环1和2)。因此,在外部for循环中,您需要为j
设置最大值,我们称之为a
。然后,内部循环需要像这样看起来:for( j in 1:a)
。通过使用模运算符(见维基百科“模运算”),您可以检查i
是否为奇数:if( i %% 2 ) ...
。 - akrafif( i %% 2 == 1)
来检查 i 是否为奇数... - akraf