it-swarm-es.tech

¿Cómo acceder al último valor en un vector?

Supongamos que tengo un vector que está anidado en un marco de datos de uno o dos niveles. ¿Existe una forma rápida y sucia de acceder al último valor sin utilizar la función length()? Algo ala $# special var de Perl?

Así que me gustaría algo como:

dat$vec1$vec2[$#]

en lugar de

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

Yo uso la función tail():

tail(vector, n=1)

Lo bueno de tail() es que también funciona en marcos de datos, a diferencia del idioma x[length(x)].

314
lindelof

Para responder a esto no desde un punto de vista estético sino orientado hacia el rendimiento, he puesto todas las sugerencias anteriores a través de un punto de referencia . Para ser precisos, he considerado las sugerencias.

  • x[length(x)]
  • mylast(x), donde mylast es una función de C++ implementada a través de Rcpp,
  • tail(x, n=1)
  • dplyr::last(x)
  • x[end(x)[1]]]
  • rev(x)[1]

y los aplicó a vectores aleatorios de varios tamaños (10 ^ 3, 10 ^ 4, 10 ^ 5, 10 ^ 6 y 10 ^ 7). Antes de ver los números, creo que debería quedar claro que cualquier cosa que se vuelva notablemente más lenta con un mayor tamaño de entrada (es decir, cualquier cosa que no sea O(1)) no es una opción. Aquí está el código que utilicé:

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

Me da

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

Esto descarta de inmediato cualquier cosa relacionada con rev o end, ya que claramente no son O(1) (y las expresiones resultantes se evalúan de manera no perezosa). tail y dplyr::last no están lejos de ser O(1) pero también son considerablemente más lentos que mylast(x) y x[length(x)]. Ya que mylast(x) es más lento que x[length(x)] y no proporciona beneficios (más bien, es personalizado y no maneja con gracia un vector vacío), creo que la respuesta es clara: Por favor use x[length(x)].

126
anonymous

Si estás buscando algo tan bonito como la notación x [-1] de Python, creo que no tienes suerte. El idioma estándar es

x[length(x)]  

pero es bastante fácil escribir una función para hacer esto:

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

Esta característica que falta en R me molesta también!

99
Gregg Lind

Combinando las ideas de lindelof y gregg lind:

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

Trabajando en el indicador, normalmente omito el "n=", es decir, tail(x, 1).

A diferencia de last del paquete pastecs, head y tail (de utils) funcionan no solo en vectores sino también en marcos de datos, etc., y también pueden devolver datos "sin los elementos primero/último n", por ejemplo.

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

(Tenga en cuenta que tiene que usar head para esto, en lugar de tail.)

43
Florian Jenn

Acabo de comparar estos dos enfoques en el marco de datos con 663,552 filas usando el siguiente código:

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 

y

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 

Entonces, asumiendo que estás trabajando con vectores, acceder a la posición de longitud es significativamente más rápido.

17
scuerda

El paquete dplyr incluye una función last():

last(mtcars$mpg)
# [1] 21.4
16
Sam Firke

Otra forma es tomar el primer elemento del vector invertido:

rev(dat$vect1$vec2)[1]
12
James

Tengo otro método para encontrar el último elemento en un vector. Digamos que el vector es 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

¡Ahí tienes!

9
Akash

De que se trata

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

El paquete data.table incluye la función last

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

El paquete xts proporciona una función last:

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