Si, por el bien del argumento, quiero los últimos cinco elementos de un vector de 10 longitudes en Python, puedo usar el operador "-" en el índice de rango así:
>>> x = range(10)
>>> x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> x[-5:]
[5, 6, 7, 8, 9]
>>>
¿Cuál es la mejor forma de hacer esto en R? ¿Existe una forma más limpia que mi técnica actual que es usar la función 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
>
La pregunta está relacionada con el análisis de series de tiempo por cierto, donde a menudo es útil trabajar solo con datos recientes.
x[seq.int(to=length(x), length.out=5)]
parece ser 10 veces más rápida que,tail()
pero sin los controles de cordura;x[length(x)-(4:0)]
es aún más rápido.Puede hacer exactamente lo mismo en R con dos caracteres más:
x <- 0:9 x[-5:-1] [1] 5 6 7 8 9
o
x[-(1:5)]
fuente
x <- 0:20; x[-5:-1]
- esto devuelve los últimos quince elementos.x[-5:]
: ¿esto significa omitir los primeros 5 elementos o mantener los últimos 5? Si es el primero, indirectamente está usando tu longitud, como tú, aquí (de lo contrario, ¿cómo sabes qué elementos omitir?)tail
es lo que quieres entonces.La desaprobación de
tail
aquí basada solo en la velocidad realmente no parece enfatizar que parte de la velocidad más lenta proviene del hecho de que es más seguro trabajar con la cola, si no está seguro de que la longitud de x excederán
el número de elementos que desea subconjuntos: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
Tail simplemente devolverá el número máximo de elementos en lugar de generar un error, por lo que no es necesario que realice ninguna comprobación de errores usted mismo. Una gran razón para usarlo. Código más seguro y más limpio, si los microsegundos / milisegundos adicionales no le importan mucho en su uso.
fuente
¿Qué tal
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
fuente
x <- 1:10e6
Aquí hay una función para hacerlo y parece razonablemente rápida.
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)] } }
USO:
test<-c(0,1,1,0,0,1,1,NA,1,1) endv(test,5) endv(LETTERS,5)
PUNTO DE REFERENCIA:
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
fuente
Solo agrego aquí algo relacionado. Quería acceder a un vector con índices de backend, es decir, escribir algo como
tail(x, i)
pero para volverx[length(x) - i + 1]
y no toda la cola.Después de los comentarios, comparé dos soluciones:
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
Entonces, en este caso parece que incluso para vectores pequeños,
tail
es muy lento en comparación con el acceso directofuente