2008-09-16 23 views
194

Supongamos que tengo un vector anidado en un marco de datos uno o dos niveles. ¿Hay una forma rápida y sucia de acceder al último valor, sin usar la función length()? Algo a la var especial $# de PERL?¿Cómo acceder al último valor en un vector?

Así que me gustaría algo así como:

dat$vec1$vec2[$#] 

en lugar de

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

relacionadas: http://stackoverflow.com/q/613 6613/946850 – krlmlr

+1

MATLAB tiene la notación "mivariable (end-k)" donde k es un número entero menor que la longitud del vector que devolverá el elemento (length (myvariable) -k) th. Eso sería bueno tener en R. – EngrStudent

+0

No soy de ninguna manera un experto en R, pero un rápido Google apareció esto: Parece haber una "última" función. – benefactual

Respuesta

82

Si usted está buscando algo tan bonito como x de Python [-1] notación, creo que eres sin suerte. El lenguaje estándar es

x[length(x)] 

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

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

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

262

utilizo la función tail():

tail(vector, n=1) 

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

+3

sin embargo x [longitud (x [, 1]),] funciona en marcos de datos o x [dim (x) [1],] – kpierce8

+19

Tenga en cuenta que para marcos de datos, length (x) == ncol (x) así que definitivamente incorrecto, y dim (x) [1] puede escribirse más descriptivamente nrow (x). – hadley

+1

@hadley - la sugerencia de kpierce8 de 'x [length (x [, 1]),]' no está mal (observe la coma en el subconjunto 'x'), pero ciertamente es incómodo. – jbaums

41

La combinación de Lindelof y las ideas de Gregg Lind:

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

de trabajo en el indicador, por lo general omiten el "n=", es decir tail(x, 1).

diferencia de last del paquete pastecs, head y tail (de utils) trabajar no sólo en los vectores, sino también en tramas de datos etc., y también puede devolver datos "sin primero/último n elementos", por ejemplo,

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

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

+3

Tenga en cuenta que mi punto de referencia a continuación muestra que esto es más lento que 'x [longitud (x)]' por un factor de 30 en promedio para vectores más grandes. – anonymous

13

Otra forma es tomar el primer elemento del vector invertido:

rev(dat$vect1$vec2)[1] 
+5

¡Sin embargo, esto será * costoso *! –

+1

Tenga en cuenta que esta es una operación cuyo costo computacional es lineal en la longitud de la entrada; en otras palabras, mientras O (n), no es O (1). Ver también mi punto de referencia a continuación para conocer los números reales. – anonymous

+0

@anonymous A menos que use un iterador – James

17

acabo Benchmarked estos dos enfoques en el marco de datos con 663.552 filas utilizando 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 

Así, suponiendo que se trabaja con vectores, el acceso a la posición de longitud es significativamente más rápido.

+3

¿Por qué no probar 'tail (strsplit (x,". ", Fixed = T) [[1]], 1)' para el segundo caso? Para mí, la principal ventaja de la 'cola' es que puedes escribirla en una línea. ;) – mschilli

8

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

¡Ahi lo tienes!

6

Cuál es sobre

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

Aprecio que 'NROW' haga lo que cabría esperar en muchos tipos de datos diferentes, pero es esencialmente lo mismo que' a [length (a)] 'que OP espera evitar. Usando el ejemplo de OP de un vector anidado, 'dat $ vec1 $ vec2 [NROW (dat $ vec1 $ vec2)]' sigue siendo bastante desordenado. – Gregor

+0

se puede escribir como 'nrow' –

52

Para responder a esta no desde un punto de vista estético, pero orientado al 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 implementada a través RCPP C++,
  • 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 debe quedar claro que cualquier cosa que se vuelva notablemente más lenta con un tamaño de entrada mayor (es decir, cualquier cosa que no sea O (1)) no es una opción. Aquí está el código que he utilizado:

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 inmediatamente cualquier cosa que implica rev o end ya que son claramente no O(1) (y las expresiones resultantes se evalúan en un no -la moda relajada). 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)]. Como mylast(x) es más lento que x[length(x)] y no proporciona ningún beneficio (más bien, es personalizado y no maneja un vector vacío con gracia), creo que la respuesta es clara: Utilice x[length(x)].

+5

^O (1) las soluciones deben ser la única respuesta aceptable en esta pregunta. – Kwame

6

paquete data.table incluye last función

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

Esto básicamente se reduce a 'x [[length (x)]]' de nuevo. –

11

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

last(mtcars$mpg) 
# [1] 21.4 
+2

Esto básicamente se reduce a 'x [[length (x)]]' de nuevo. –

+2

Similar bajo el capó, pero con esta respuesta no tiene que escribir su propia función 'last()' y almacenar esa función en algún lugar, como varias personas lo han hecho anteriormente. Obtiene la legibilidad mejorada de una función, con la portabilidad de la que proviene de CRAN para que otra persona pueda ejecutar el código. –

+1

También se puede escribir como 'mtcars $ mpg%>% last', según sus preferencias. –

1

El paquete XTS proporciona una función last:

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