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

Posted

技术标签:

【中文标题】如何访问向量中的最后一个值?【英文标题】:How to access the last value in a vector? 【发布时间】:2010-09-09 19:08:41 【问题描述】:

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

所以我想要类似的东西:

dat$vec1$vec2[$#]

而不是

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

【问题讨论】:

我绝不是 R 专家,但一个快速的谷歌发现了这个:stat.ucl.ac.be/ISdidactique/Rhelp/library/pastecs/html/…> 似乎有一个“最后”功能。 相关:***.com/q/6136613/946850 MATLAB 具有符号“myvariable(end-k)”,其中 k 是一个小于将返回第 (length(myvariable)-k) 个元素的向量长度的整数。在 R 中会很好。 【参考方案1】:

我使用tail函数:

tail(vector, n=1)

tail 的好处在于它也适用于数据帧,这与 x[length(x)] 习语不同。

【讨论】:

然而 x[length(x[,1]),] 适用于数据帧或 x[dim(x)[1],] 请注意,对于数据帧,length(x) == ncol(x) 所以这肯定是错误的,dim(x)[1] 可以更描述性地写成 nrow(x)。 @hadley - kpierce8 对x[length(x[,1]),] 的建议没有错(注意x 子集中的逗号),但肯定很尴尬。 请注意,我在下面的基准测试表明,对于较大的向量,它比 x[length(x)] 平均慢 30 倍! 如果你想通过tail(vector, n=1)-tail(vector, n=2)从向量中添加东西,则不起作用【参考方案2】:

为了回答这个问题,不是从美学角度而是从性能导向的角度来看,我将上述所有建议都放在了一个基准中。确切地说,我已经考虑了这些建议

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

这立即排除了任何涉及revend 的内容,因为它们显然不是O(1)(并且结果表达式以非惰性方式评估)。 taildplyr::lastO(1) 相差不远,但它们也比 mylast(x)x[length(x)] 慢得多。由于mylast(x)x[length(x)] 慢并且没有任何好处(相反,它是自定义的并且不能优雅地处理空向量),我认为答案很明确:请使用x[length(x)]

【讨论】:

^ O(1) 解决方案应该是这个问题中唯一可接受的答案。 感谢您安排所有这些匿名 +1! 我试过mylastR=function(x) x[length(x)在Rcpp中比mylast快,但比直接写x[length(x)]慢一倍 即使使用大向量也没有有意义的差异。转换为秒表明,对于最长的向量,最快的方法需要 0.000001133 秒,最慢的方法需要 0.102328667 秒(均为中位数)。好吧,在现实生活中没有人会注意到这一点。我会在这里选择可读性而不是基准。【参考方案3】:

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

x[length(x)]  

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

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

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

【讨论】:

请注意,如果您需要向量的最后几个元素而不仅仅是最后一个元素,则在调整此解决方案时无需执行任何复杂操作。 R 的矢量化允许你做一些事情,比如通过 x[length(x)-0:3] 获取 x 的最后四个元素。【参考方案4】:

结合lindelof's 和Gregg Lind's 的想法:

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

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

pastecs 包中的last 不同,headtail(来自utils)不仅适用于向量,还适用于数据帧等,并且还可以返回数据“无需第一个/最后 n 个元素”,例如

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

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

【讨论】:

请注意,我在下面的基准测试表明,对于较大的向量,它比 x[length(x)] 平均慢 30 倍!【参考方案5】:

dplyr 包包含一个函数last()

last(mtcars$mpg)
# [1] 21.4

【讨论】:

这基本上归结为x[[length(x)]] 在引擎盖下类似,但有了这个答案,您不必编写自己的函数 last() 并将该函数存储在某处,就像上面几个人所做的那样。您可以提高函数的可读性,它的可移植性来自 CRAN,以便其他人可以运行代码。 也可以写成mtcars$mpg %&gt;% last,这取决于你的喜好。 @RichScriven 不幸的是,它比x[[length(x)]] 慢得多!【参考方案6】:

我刚刚使用以下代码在 663,552 行的数据帧上对这两种方法进行了基准测试:

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 

因此,假设您使用向量,访问长度位置会明显更快。

【讨论】:

为什么不为第二种情况测试tail(strsplit(x,".",fixed=T)[[1]],1)?对我而言,tail 的主要优点是您可以将其写在一行中。 ;)【参考方案7】:

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

rev(dat$vect1$vec2)[1]

【讨论】:

不过这会 请注意,这是一个计算成本与输入长度成线性关系的操作;换句话说,虽然 O(n),但不是 O(1)。另请参阅下面的基准以了解实际数字。 @anonymous 除非你使用迭代器 @James 对。但在那种情况下,你的代码也不会工作,不是吗?如果迭代器是指 iterators 包提供的内容,那么 (1) 您不能使用 [1] 访问第一个元素,并且 (2) 虽然您可以将 rev 应用于迭代器,但它的行为与预期不同:它只是将迭代器对象视为其成员的列表并将其反转。【参考方案8】:

我有另一种方法可以找到向量中的最后一个元素。 假设向量是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

你去!

【讨论】:

【参考方案9】:

data.table包含last函数

library(data.table)
last(c(1:10))
# [1] 10

【讨论】:

这基本上归结为x[[length(x)]]【参考方案10】:

关于什么

> a <- c(1:100,555)
> a[NROW(a)]
[1] 555

【讨论】:

我很欣赏NROW 在许多不同的数据类型上的表现,但它与 OP 希望避免的a[length(a)] 基本相同。使用 OP 的嵌套向量示例,dat$vec1$vec2[NROW(dat$vec1$vec2)] 仍然很混乱。 可以写成nrow 注意:与nrow 不同,NROW 将向量视为一列矩阵。【参考方案11】:

xts 包提供了last 函数:

library(xts)
a <- 1:100
last(a)
[1] 100

【讨论】:

以上是关于如何访问向量中的最后一个值?的主要内容,如果未能解决你的问题,请参考以下文章

for循环仅检查向量中的最后一个值以使用R检查SQL Server中的重复项?

如何清除向量中的所有元素,除了C++中向量中的最后一个元素

在 Matlab 中访问单元格中的向量

将文件中的双值数字读入 C++ 中的向量并访问它们的值

如何从vba中的数组中获取一维向量

如何更改向量中元素的值?