如何访问向量中的最后一个值?


288

假设我有一个向量嵌套在一个或两个级别的数据框中。有没有使用该length()函数的快速而肮脏的方法来访问最后一个值?是PERL的$#特殊变种吗?

所以我想要这样的东西:

dat$vec1$vec2[$#]

代替

dat$vec1$vec2[length(dat$vec1$vec2)]

1
我绝不是R专家,但是一个快速的Google提出了这个建议:< stat.ucl.ac.be/ISdidactique/Rhelp/library/pastecs/html / ... >似乎有一个“最后一个”功能。
受益人


1
MATLAB的符号为“ myvariable(end-k)”,其中k是小于将返回第(length(myvariable)-k)个元素的向量长度的整数。这将是不错的R.
EngrStudent

Answers:


369

我使用的tail功能:

tail(vector, n=1)

用的好处tail是,它可以在dataframes也不像x[length(x)]成语。


5
但是x [length(x [,1]),]适用于数据帧或x [dim(x)[1],]
kpierce8

29
请注意,对于数据帧,length(x)== ncol(x)绝对是错误的,并且dim(x)[1]可以更具描述性地写为nrow(x)。
hadley

2
@hadley-kpierce8的建议x[length(x[,1]),]没有错(请注意x子集中的逗号),但肯定很尴尬。
jbaums 2015年

4
请注意,以下我的基准显示,x[length(x)]对于较大的向量,此速度平均要慢30倍!
匿名

1
如果您想从矢量中添加内容,则不起作用tail(vector, n=1)-tail(vector, n=2)
Andreas Storvik Strauman

178

为了不是从美学角度而是以性能为导向来回答这个问题,我已经将上述所有建议通过一个基准进行了测试。确切地说,我已经考虑了建议

  • x[length(x)]
  • mylast(x),其中mylast是通过Rcpp实现的C ++函数,
  • tail(x, n=1)
  • dplyr::last(x)
  • x[end(x)[1]]]
  • rev(x)[1]

并将它们应用于各种大小的随机向量(10 ^ 3、10 ^ 4、10 ^ 5、10 ^ 6和10 ^ 7)。在查看这些数字之前,我认为应该清楚,任何在输入大小较大时变得明显变慢的事物(即,不是O(1)的事物)都不是选择。这是我使用的代码:

Rcpp::cppFunction('double mylast(NumericVector x) { int n = x.size(); return x[n-1]; }')
options(width=100)
for (n in c(1e3,1e4,1e5,1e6,1e7)) {
  x <- runif(n);
  print(microbenchmark::microbenchmark(x[length(x)],
                                       mylast(x),
                                       tail(x, n=1),
                                       dplyr::last(x),
                                       x[end(x)[1]],
                                       rev(x)[1]))}

它给我

Unit: nanoseconds
           expr   min      lq     mean  median      uq   max neval
   x[length(x)]   171   291.5   388.91   337.5   390.0  3233   100
      mylast(x)  1291  1832.0  2329.11  2063.0  2276.0 19053   100
 tail(x, n = 1)  7718  9589.5 11236.27 10683.0 12149.0 32711   100
 dplyr::last(x) 16341 19049.5 22080.23 21673.0 23485.5 70047   100
   x[end(x)[1]]  7688 10434.0 13288.05 11889.5 13166.5 78536   100
      rev(x)[1]  7829  8951.5 10995.59  9883.0 10890.0 45763   100
Unit: nanoseconds
           expr   min      lq     mean  median      uq    max neval
   x[length(x)]   204   323.0   475.76   386.5   459.5   6029   100
      mylast(x)  1469  2102.5  2708.50  2462.0  2995.0   9723   100
 tail(x, n = 1)  7671  9504.5 12470.82 10986.5 12748.0  62320   100
 dplyr::last(x) 15703 19933.5 26352.66 22469.5 25356.5 126314   100
   x[end(x)[1]] 13766 18800.5 27137.17 21677.5 26207.5  95982   100
      rev(x)[1] 52785 58624.0 78640.93 60213.0 72778.0 851113   100
Unit: nanoseconds
           expr     min        lq       mean    median        uq     max neval
   x[length(x)]     214     346.0     583.40     529.5     720.0    1512   100
      mylast(x)    1393    2126.0    4872.60    4905.5    7338.0    9806   100
 tail(x, n = 1)    8343   10384.0   19558.05   18121.0   25417.0   69608   100
 dplyr::last(x)   16065   22960.0   36671.13   37212.0   48071.5   75946   100
   x[end(x)[1]]  360176  404965.5  432528.84  424798.0  450996.0  710501   100
      rev(x)[1] 1060547 1140149.0 1189297.38 1180997.5 1225849.0 1383479   100
Unit: nanoseconds
           expr     min        lq        mean    median         uq      max neval
   x[length(x)]     327     584.0     1150.75     996.5     1652.5     3974   100
      mylast(x)    2060    3128.5     7541.51    8899.0     9958.0    16175   100
 tail(x, n = 1)   10484   16936.0    30250.11   34030.0    39355.0    52689   100
 dplyr::last(x)   19133   47444.5    55280.09   61205.5    66312.5   105851   100
   x[end(x)[1]] 1110956 2298408.0  3670360.45 2334753.0  4475915.0 19235341   100
      rev(x)[1] 6536063 7969103.0 11004418.46 9973664.5 12340089.5 28447454   100
Unit: nanoseconds
           expr      min         lq         mean      median          uq       max neval
   x[length(x)]      327      722.0      1644.16      1133.5      2055.5     13724   100
      mylast(x)     1962     3727.5      9578.21      9951.5     12887.5     41773   100
 tail(x, n = 1)     9829    21038.0     36623.67     43710.0     48883.0     66289   100
 dplyr::last(x)    21832    35269.0     60523.40     63726.0     75539.5    200064   100
   x[end(x)[1]] 21008128 23004594.5  37356132.43  30006737.0  47839917.0 105430564   100
      rev(x)[1] 74317382 92985054.0 108618154.55 102328667.5 112443834.0 187925942   100

这会立即排除所有涉及rev或的东西,end因为它们显然不是O(1)(并且以非惰性方式评估结果表达式)。tail并且dplyr::last距离并不远,O(1)但是它们也比mylast(x)和慢很多x[length(x)]。由于mylast(x)速度慢x[length(x)]且没有任何好处(相反,它是自定义的,不会优雅地处理空向量),我认为答案很明确:请使用x[length(x)]


11
^ O(1)解决方案应该是这个问题中唯一可接受的答案。
夸梅

2
感谢您为所有这些+1计时!
山姆

1
我尝试过mylastR=function(x) {x[length(x)}它比mylastRcpp 快,但比x[length(x)]直接编写慢一倍
Endle_Zhenbo,

115

如果您正在寻找与Python的x [-1]表示法一样好的东西,我认为您很不走运。标准成语是

x[length(x)]  

但是编写一个函数来做到这一点很容易:

last <- function(x) { return( x[length(x)] ) }

R中缺少的这个功能也让我很烦!


3
提供函数示例+1的好主意
-H.Latte,

请注意,如果您想要向量的最后几个元素,而不仅仅是最后一个元素,那么在采用此解决方案时无需做任何复杂的事情。R的向量化功能可让您做一些有趣的事情,例如,x通过做来获取的最后四个元素x[length(x)-0:3]
J. Mini

46

结合lindelofGregg Lind的想法:

last <- function(x) { tail(x, n = 1) }

在提示符下工作时,我通常会忽略n=,即tail(x, 1)

lastfrom pastecs包不同,headand tail(from utils)不仅适用于矢量,而且适用于数据帧等,并且还可以返回数据“ 不带前/后n个元素 ”,例如

but.last <- function(x) { head(x, n = -1) }

(请注意,您必须使用head而不是tail。)


7
请注意,下面的基准测试显示,x[length(x)]对于较大的向量,此速度平均要慢30倍!
匿名

19

所述dplyr封装包括功能last()

last(mtcars$mpg)
# [1] 21.4

4
这基本上可以归结为x[[length(x)]]
Rich Scriven

6
内幕相似,但是有了这个答案,您不必编写自己的函数last()并将该函数存储在某个地方,就像上面几个人所做的那样。您可以从CRAN中获得功能的可移植性,从而提高了功能的可读性,以便其他人可以运行代码。
Sam Firke '16

1
也可以写成mtcars$mpg %>% last,具体取决于您的偏好。
基思·休吉特

1
@RichScriven不幸的是,它比慢得多x[[length(x)]]
匿名

18

我只是使用以下代码在663552行的数据帧上对这两种方法进行了基准测试:

system.time(
  resultsByLevel$subject <- sapply(resultsByLevel$variable, function(x) {
    s <- strsplit(x, ".", fixed=TRUE)[[1]]
    s[length(s)]
  })
  )

 user  system elapsed 
  3.722   0.000   3.594 

system.time(
  resultsByLevel$subject <- sapply(resultsByLevel$variable, function(x) {
    s <- strsplit(x, ".", fixed=TRUE)[[1]]
    tail(s, n=1)
  })
  )

   user  system elapsed 
 28.174   0.000  27.662 

因此,假设您正在使用向量,则访问长度位置的速度明显更快。


3
为什么不测试tail(strsplit(x,".",fixed=T)[[1]],1)第二种情况?对我来说,的主要优点tail是您可以将其编写为一行。;)
mschilli 2014年

13

另一种方法是采用反向向量的第一个元素:

rev(dat$vect1$vec2)[1]

7
这将是昂贵的
费利佩·杰拉德

1
请注意,这是一个运算,其计算成本在输入长度上是线性的;换句话说,虽然O(n)不是O(1)。另请参阅我的基准以获取实际数字。
匿名

@anonymous除非您使用迭代器
詹姆斯

@詹姆斯右。但是在那种情况下,您的代码也不起作用,对吗?如果用迭代器表示由迭代器包提供的内容,则(1)您不能[1]用来访问第一个元素,而(2)可以应用rev到迭代器时,它的行为不符合预期:它只是将iterator对象视为它的成员列表,并将其反转。
匿名


10

我有另一种方法来查找向量中的最后一个元素。假设向量为a

> a<-c(1:100,555)
> end(a)      #Gives indices of last and first positions
[1] 101   1
> a[end(a)[1]]   #Gives last element in a vector
[1] 555

你去!



3

xts包提供了一个last功能:

library(xts)
a <- 1:100
last(a)
[1] 100
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.