Jeśli ze względu na argumenty chcę ostatnich pięciu elementów wektora o długości 10 w Pythonie, mogę użyć operatora „-” w indeksie zakresu, więc:
>>> x = range(10)
>>> x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> x[-5:]
[5, 6, 7, 8, 9]
>>>
Jaki jest najlepszy sposób na zrobienie tego w R? Czy istnieje bardziej przejrzysty sposób niż moja obecna technika, która polega na użyciu funkcji 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
>
Pytanie dotyczy analizy szeregów czasowych, przy czym często przydaje się praca tylko na najnowszych danych.
x[seq.int(to=length(x), length.out=5)]
wydaje się być około 10x szybsza niż,tail()
ale bez sprawdzania poprawności ;x[length(x)-(4:0)]
jest jeszcze szybszy.Możesz zrobić dokładnie to samo w R z dwoma dodatkowymi postaciami:
x <- 0:9 x[-5:-1] [1] 5 6 7 8 9
lub
x[-(1:5)]
źródło
x <- 0:20; x[-5:-1]
- zwraca piętnaście ostatnich elementów.x[-5:]
: czy to oznacza pominięcie pierwszych 5 elementów, czy zachowanie ostatnich 5? Jeśli to pierwszy, pośrednio używa twojej długości, tak jak ty, tutaj (w przeciwnym razie, skąd wiesz, które elementy pominąć?)tail
.Dezaprobata
tail
tutaj oparta na samej prędkości nie wydaje się tak naprawdę podkreślać, że część wolniejszej prędkości wynika z faktu, że praca z ogonem jest bezpieczniejsza, jeśli nie masz pewności, że długość x przekroczyn
liczbę elementów, które chcesz wydzielić: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 zwróci po prostu maksymalną liczbę elementów zamiast generować błąd, więc nie musisz samodzielnie sprawdzać błędów. Świetny powód, aby go używać. Bezpieczniejszy i czystszy kod, jeśli dodatkowe mikrosekundy / milisekundy nie mają dla ciebie większego znaczenia w jego użyciu.
źródło
A co powiesz
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
źródło
x <- 1:10e6
Oto funkcja, która to robi i wydaje się dość szybka.
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)] } }
STOSOWANIE:
test<-c(0,1,1,0,0,1,1,NA,1,1) endv(test,5) endv(LETTERS,5)
REPER:
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
źródło
Dodam tu tylko coś związanego. Chciałem uzyskać dostęp do wektora z indeksami zaplecza, tj. Napisać coś podobnego,
tail(x, i)
ale zwrócić,x[length(x) - i + 1]
a nie cały ogon.Po komentarzach porównałem dwa rozwiązania:
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
Wydaje się więc w tym przypadku, że nawet dla małych wektorów
tail
jest bardzo wolny w porównaniu z dostępem bezpośrednimźródło