Получение последних n элементов вектора. Есть ли лучший способ, чем использовать функцию length ()? - PullRequest
71 голосов
/ 26 мая 2011

Если ради аргумента мне нужны последние пять элементов вектора 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
> 

Вопрос связан с анализом временных рядов, где часто бывает полезно работать только с последними данными.

Ответы [ 6 ]

99 голосов
/ 26 мая 2011

см. ?tail и ?head для некоторых удобных функций:

> x <- 1:10
> tail(x,5)
[1]  6  7  8  9 10

Ради аргумента: все, кроме последних пяти элементов, будет:

> head(x,n=-5)
[1] 1 2 3 4 5

As @Мартин Морган говорит в комментариях, что есть две другие возможности, которые быстрее, чем хвостовое решение, на случай, если вам придется выполнить это миллион раз на векторе 100 миллионов значений.Для наглядности я бы пошел с хвостом.

test                                        elapsed    relative 
tail(x, 5)                                    38.70     5.724852     
x[length(x) - (4:0)]                           6.76     1.000000     
x[seq.int(to = length(x), length.out = 5)]     7.53     1.113905     

код бенчмаркинга:

require(rbenchmark)
x <- 1:1e8
do.call(
  benchmark,
  c(list(
    expression(tail(x,5)),
    expression(x[seq.int(to=length(x), length.out=5)]),
    expression(x[length(x)-(4:0)])
  ),  replications=1e6)
)
5 голосов
/ 24 апреля 2017

Неудовлетворительное 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

Хвост просто вернет максимальное количество элементов вместо генерации ошибки, поэтому вам не нужно делать никакихпроверка ошибок самостоятельно.Отличная причина для его использования.Более безопасный код, если дополнительные микросекунды / миллисекунды не имеют большого значения для вас при его использовании.

4 голосов
/ 26 мая 2011

Вы можете сделать то же самое в R с еще двумя символами:

x <- 0:9
x[-5:-1]
[1] 5 6 7 8 9

или

x[-(1:5)]
3 голосов
/ 17 августа 2017

Как насчет 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
2 голосов
/ 19 января 2016

Я просто добавляю сюда что-то связанное.Я хотел получить доступ к вектору с индексами бэкэнда, то есть написать что-то вроде 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 очень медленный по сравнению с прямым доступом

2 голосов
/ 05 августа 2013

Вот функция, которая делает это, и кажется достаточно быстрой.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...