Если в качестве аргумента мне нужны последние пять элементов вектора длиной 10 в Python, я могу использовать оператор «-» в индексе диапазона, чтобы:
>>> x = range(10)
>>> x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> x[-5:]
[5, 6, 7, 8, 9]
>>>
Как лучше всего это сделать в R? Есть ли более чистый способ, чем моя нынешняя техника, - использовать функцию 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
>
Вопрос связан с анализом временных рядов, кстати, где часто бывает полезно работать только с недавними данными.
x[seq.int(to=length(x), length.out=5)]
кажется примерно в 10 раз быстрее, чемtail()
без проверок работоспособности ;x[length(x)-(4:0)]
еще быстрее.Вы можете сделать то же самое в R с двумя другими персонажами:
x <- 0:9 x[-5:-1] [1] 5 6 7 8 9
или же
x[-(1:5)]
источник
x <- 0:20; x[-5:-1]
- возвращает последние пятнадцать элементов.x[-5:]
: означает ли это пропустить первые 5 элементов или оставить последние 5? Если это первый, он косвенно использует вашу длину, как и вы здесь (иначе, как узнать, какие элементы пропустить?)tail
- это то, что вам тогда нужно.Неудобство
tail
здесь, основанное только на скорости, на самом деле, похоже, не подчеркивает, что часть более низкой скорости происходит из того факта, что с хвостом безопаснее работать, если вы не уверены, что длина x превыситn
, число элементов, которые вы хотите выделить: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 просто вернет максимальное количество элементов вместо того, чтобы генерировать ошибку, поэтому вам не нужно самостоятельно проверять ошибки. Отличный повод его использовать. Более безопасный чистый код, если дополнительные микросекунды / миллисекунды не имеют для вас большого значения при его использовании.
источник
Как насчет
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
источник
x <- 1:10e6
Вот функция для этого, и она кажется достаточно быстрой.
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)] } }
ПРИМЕНЕНИЕ:
test<-c(0,1,1,0,0,1,1,NA,1,1) endv(test,5) endv(LETTERS,5)
ЭТАЛОН:
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
источник
Я просто добавляю сюда кое-что связанное с этим. Мне нужно было получить доступ к вектору с индексами бэкэнда, т.е. написать что-то вроде,
tail(x, i)
но чтобы вернутьx[length(x) - i + 1]
а не весь хвост.Следуя комментариям, я протестировал два решения:
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
Таким образом, в этом случае оказывается, что даже для небольших векторов
tail
это очень медленно по сравнению с прямым доступомисточник