获取vector的最后n个元素。 有没有比使用length()函数更好的方法?

如果为了参数的缘故,我想要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 > 

这个问题是关于时间序列分析顺便说一句,通常只有在最近的数据工作是有用的。

看到?tail?head来获得一些方便的function:

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

为了论证的缘故:除了最后五个元素之外,其他的都是:

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

正如@Martin Morgan在评论中所说的那样,还有另外两种可能性比尾部解决scheme更快,万一你必须在1亿个值的vector上进行一百万次这样的事情。 为了可读性,我会去尾巴。

 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) ) 

您可以在R中使用两个以上的字符完成同样的事情:

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

要么

 x[-(1:5)] 

这里仅基于速度而不赞同tail似乎并没有强调速度较慢的部分来自尾部更安全的事实,如果你不确定x的长度是否会超过n ,你想要子集的元素的数量:

 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 

尾巴将简单地返回元素的最大数量,而不是产生一个错误,所以你不需要做自己的错误检查。 使用它的一个很好的理由。 更安全的更清洁的代码,如果额外的微秒/毫秒对你的使用无关紧要。

这是一个function,它看起来相当快。

 endv<-function(vec,val) { if(val>length(vec)) { stop("Length of value greater than length of vector") }else { vec[((length(vec)-val)+1):length(vec)] } } 

用法:

 test<-c(0,1,1,0,0,1,1,NA,1,1) endv(test,5) endv(LETTERS,5) 

风向标:

  test replications elapsed relative 1 expression(tail(x, 5)) 100000 5.24 6.469 2 expression(x[seq.int(to = length(x), length.out = 5)]) 100000 0.98 1.210 3 expression(x[length(x) - (4:0)]) 100000 0.81 1.000 4 expression(endv(x, 5)) 100000 1.37 1.691 

我只是在这里添加相关的东西。 我想要访问一个带有后端索引的向量,也就是像tail(x, i)那样写入,但返回x[length(x) - i + 1]而不是整个尾部。

在评论之后,我以两个解决scheme为基准:

 accessRevTail <- function(x, n) { tail(x,n)[1] } accessRevLen <- function(x, n) { x[length(x) - n + 1] } microbenchmark::microbenchmark(accessRevLen(1:100, 87), accessRevTail(1:100, 87)) Unit: microseconds expr min lq mean median uq max neval accessRevLen(1:100, 87) 1.860 2.3775 2.84976 2.803 3.2740 6.755 100 accessRevTail(1:100, 87) 22.214 23.5295 28.54027 25.112 28.4705 110.833 100 

因此,在这种情况下,即使对于小向量,与直接访问相比, tail也是非常慢的

rev(x)[1:5]怎么样?

 x<-1:10 system.time(replicate(10e6,tail(x,5))) user system elapsed 138.85 0.26 139.28 system.time(replicate(10e6,rev(x)[1:5])) user system elapsed 61.97 0.25 62.23