我希望在R中使用rep
函数或其他函数按照以下顺序进行操作。
c(1, 2, 3, 4, 5, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5)
基本上,c(1:5, 2:5, 3:5, 4:5, 5:5)
。
使用sequence
。
sequence(5:1, from = 1:5)
[1] 1 2 3 4 5 2 3 4 5 3 4 5 4 5 5
第一个参数nvec
表示每个序列的长度(例如:5:1
),第二个参数from
表示每个序列的起始点(例如:1:5
)。
注意:这仅适用于R版本大于或等于4.0.0。来自R News 4.0.0的介绍:
sequence()
[...]增加了参数[例如from
],以生成更复杂的序列。
unlist(lapply(1:5, function(i) i:5))
# [1] 1 2 3 4 5 2 3 4 5 3 4 5 4 5 5
对所有提供的答案进行速度测试 请注意,如果我没有记错,OP在某处提到了10K
s1 <- function(n) {
unlist(lapply(1:n, function(i) i:n))
}
s2 <- function(n) {
unlist(lapply(seq_len(n), function(i) seq(from = i, to = n, by = 1)))
}
s3 <- function(n) {
vect <- 0:n
unlist(replicate(n, vect <<- vect[-1]))
}
s4 <- function(n) {
m <- matrix(1:n, ncol = n, nrow = n, byrow = TRUE)
m[lower.tri(m)] <- 0
c(t(m)[t(m != 0)])
}
s5 <- function(n) {
m <- matrix(seq.int(n), ncol = n, nrow = n)
m[lower.tri(m, diag = TRUE)]
}
s6 <- function(n) {
out <- c()
for (i in 1:n) {
out <- c(out, (1:n)[i:n])
}
out
}
library(rbenchmark)
n = 5
n = 5L
benchmark(
"s1" = { s1(n) },
"s2" = { s2(n) },
"s3" = { s3(n) },
"s4" = { s4(n) },
"s5" = { s5(n) },
"s6" = { s6(n) },
replications = 1000,
columns = c("test", "replications", "elapsed", "relative")
)
不要被一些“快速”解决方案所欺骗,这些解决方案几乎没有需要调用时间的函数,而且差异会被1000倍的复制放大。
test replications elapsed relative
1 s1 1000 0.05 2.5
2 s2 1000 0.44 22.0
3 s3 1000 0.14 7.0
4 s4 1000 0.08 4.0
5 s5 1000 0.02 1.0
6 s6 1000 0.02 1.0
n = 1000
n = 1000L
benchmark(
"s1" = { s1(n) },
"s2" = { s2(n) },
"s3" = { s3(n) },
"s4" = { s4(n) },
"s5" = { s5(n) },
"s6" = { s6(n) },
replications = 10,
columns = c("test", "replications", "elapsed", "relative")
)
如楼主所说的“不要使用”的方法,我们发现在 n = 1000L
的情况下,for
循环明显比其它方法慢。
test replications elapsed relative
1 s1 10 0.17 1.000
2 s2 10 0.83 4.882
3 s3 10 0.19 1.118
4 s4 10 1.50 8.824
5 s5 10 0.29 1.706
6 s6 10 28.64 168.471
n = 10000
n = 10000L
benchmark(
"s1" = { s1(n) },
"s2" = { s2(n) },
"s3" = { s3(n) },
"s4" = { s4(n) },
"s5" = { s5(n) },
# "s6" = { s6(n) },
replications = 10,
columns = c("test", "replications", "elapsed", "relative")
)
在大数据量n的情况下,我们发现矩阵方法相对于其他方法变得非常缓慢。在apply中使用seq可能更加整洁,但会带来一个折衷——调用该函数n次会大大增加处理时间。尽管seq_len(n)比1:n更好,而且只运行一次。有趣的是,replicate方法是最快的。
test replications elapsed relative
1 s1 10 5.44 1.915
2 s2 10 9.98 3.514
3 s3 10 2.84 1.000
4 s4 10 72.37 25.482
5 s5 10 35.78 12.599
unlist(lapply(1:10, function(i) i:5))
是不正确的。将第二个参数更改为 function(i) seq(from = i, to = 5, by = 1)
更冗长,但更安全。最终版本可能是 output <- function(x) unlist(lapply(seq_len(x), function(i) seq(from = i, to = x, by = 1)))
。 - J. MiniR:sequence function (nvec) unlist(lapply(nvec, seq_len))
的包装器,所以我期望它的速度与 s1 或 s2 一样。 - Merijn van Tilborgsequence
和n = 10000进行快速的system.time
测试表明,它比replicate
方法快8-9倍。 - Henrikunlist(lapply(1:5, ':', 5))
。 - Robert Hacken提到您的rep
让我想起replicate
,所以这里是一个非常有状态的解决方案。 我呈现这个方案是因为它很短而且不寻常,而不是因为它好。 这是非常不典型的R。
vect <- 0:5
unlist(replicate(5, vect <<- vect[-1]))
[1] 1 2 3 4 5 2 3 4 5 3 4 5 4 5 5
rep
和lapply
来完成,但基本上与Merijn van Tilborg的答案相同。mat <- matrix(1:5, ncol = 5, nrow = 5, byrow = TRUE)
mat[lower.tri(mat)] <- 0
c(t(mat)[t(mat != 0)])
[1] 1 2 3 4 5 2 3 4 5 3 4 5 4 5 5
m = matrix(seq.int(n), ncol = n, nrow = n)
;m[lower.tri(m, diag = TRUE)]
(虽然不太习惯这种写法)。 - Henrikbyrow=TRUE
时,我不得不两次调用 t
时,我就知道有些不对劲了。 - J. Miniupper/lower.tri
/byrow
/"to t
or not to t
"的迷宫中迷失过。非典型的贡献非常受欢迎。 - Henrikrow(m)>=col(m)
进行高尔夫球练习。 - Henrikout=c();for(i in 1:5){ out=c(out, (1:5)[i:5]) }
out
# [1] 1 2 3 4 5 2 3 4 5 3 4 5 4 5 5
但那不是一个好主意!
使用循环会导致:
相比之下,使用矢量化函数如sequence
则恰好相反(速度更快、更高效,且易于阅读)。
来自?sequence
:
序列的默认方法为每个元素i在并行(和循环)向量
from
、by
和nvec
中生成序列seq(from[i], by = by[i], length.out = nvec[i])
。然后返回连接这些序列的结果。
关于from
参数:
from:每个元素指定序列的第一个元素。
此外,由于循环中使用的向量未预先分配,因此将需要更多内存,并且速度也会变慢。
sequence
进行了回答:https://stackoverflow.com/a/67887135/9463489 - jblood94