创建一系列数字序列
Create a sequence of sequences of numbers
我想使用 rep
或任何其他函数在 R 中生成以下序列。
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()
[...] gains arguments [e.g. from
] to generate more complex sequences.
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")
)
正如张贴者已经提到的“不要做”,我们看到 for
循环与任何其他方法相比变得非常慢,在 n = 1000L
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 更好,而且只是 运行 一次。有趣的是,复制方法是最快的。
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
你提到的 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 的回答基本相同。
当然,真正无畏的单一 R 用户会这样做并且拒绝进一步详细说明。
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
您可以像这样使用循环:
out=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
:
The default method for sequence generates the sequence seq(from[i], by = by[i], length.out = nvec[i])
for each element i
in the parallel (and recycled) vectors from
, by
and nvec
. It then returns the result of concatenating those sequences.
关于 from
论点:
from: each element specifies the first element of a sequence.
此外,由于循环中使用的向量未预先分配,因此需要更多内存,速度也会变慢。
我想使用 rep
或任何其他函数在 R 中生成以下序列。
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()
[...] gains arguments [e.g.from
] to generate more complex sequences.
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")
)
正如张贴者已经提到的“不要做”,我们看到 for
循环与任何其他方法相比变得非常慢,在 n = 1000L
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 更好,而且只是 运行 一次。有趣的是,复制方法是最快的。
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
你提到的 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 的回答基本相同。
当然,真正无畏的单一 R 用户会这样做并且拒绝进一步详细说明。
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
您可以像这样使用循环:
out=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
:
The default method for sequence generates the sequence
seq(from[i], by = by[i], length.out = nvec[i])
for each elementi
in the parallel (and recycled) vectorsfrom
,by
andnvec
. It then returns the result of concatenating those sequences.
关于 from
论点:
from: each element specifies the first element of a sequence.
此外,由于循环中使用的向量未预先分配,因此需要更多内存,速度也会变慢。