获取向量的最后 n 个元素,除了使用 length() 函数还有更好的方法吗?

104 投票
6 回答
149715 浏览
提问于 2025-04-16 18:23

假设我想在Python中获取一个长度为10的列表的最后五个元素,我可以像这样在范围索引中使用-运算符:

>>> x = range(10)
>>> x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> x[-5:]
[5, 6, 7, 8, 9]
>>>

那么在R中,最好的方法是什么呢?有没有比我现在使用length()函数的方法更简洁呢?

> x <- 0:9
> x
 [1] 0 1 2 3 4 5 6 7 8 9
> x[(length(x) - 4):length(x)]
[1] 5 6 7 8 9
> 

顺便提一下,这个问题与时间序列分析有关,在这种情况下,通常只需要处理最近的数据。

6 个回答

5

你可以在R语言中用两个额外的字符做到完全相同的事情:

x <- 0:9
x[-5:-1]
[1] 5 6 7 8 9

或者

x[-(1:5)]
9

这里对tail的批评主要是因为速度慢,但其实慢的原因之一是因为tail在使用时更安全。如果你不确定x的长度是否会超过n(你想要提取的元素数量),那么使用tail就很合适:

x <- 1:10
tail(x, 20)
# [1]  1  2  3  4  5  6  7  8  9 10
x[length(x) - (0:19)]
#Error in x[length(x) - (0:19)] : 
#  only 0's may be mixed with negative subscripts

因为tail会返回最多的元素,而不是报错,所以你自己就不需要进行错误检查。这是使用它的一个很好的理由。如果你不太在意多花的微秒或毫秒,使用tail可以让代码更安全、更简洁。

142

可以查看 ?tail?head 这两个函数,它们很方便:

> x <- 1:10
> tail(x,5)
[1]  6  7  8  9 10

为了说明问题:除了最后五个元素,其他的元素是:

> head(x,n=-5)
[1] 1 2 3 4 5

正如 @Martin Morgan 在评论中提到的,还有另外两种方法比使用 tail 更快,特别是当你需要在一个有一亿个值的向量上执行这个操作一百万次的时候。为了可读性,我建议使用 tail。

test                                        elapsed    relative 
tail(x, 5)                                    38.70     5.724852     
x[length(x) - (4:0)]                           6.76     1.000000     
x[seq.int(to = length(x), length.out = 5)]     7.53     1.113905     

基准测试代码:

require(rbenchmark)
x <- 1:1e8
do.call(
  benchmark,
  c(list(
    expression(tail(x,5)),
    expression(x[seq.int(to=length(x), length.out=5)]),
    expression(x[length(x)-(4:0)])
  ),  replications=1e6)
)

撰写回答