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

r indexing

95016 просмотра

6 ответа

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

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

Автор: Thomas Browne Источник Размещён: 04.10.2019 05:54

Ответы (6)


100 плюса

Решение

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

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

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

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

Как говорит @Martin Morgan в комментариях, есть две другие возможности, которые быстрее, чем хвостовое решение, на случай, если вам придется выполнить это миллион раз на векторе 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)
)
Автор: Joris Meys Размещён: 26.05.2011 09:49

5 плюса

По- 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 просто вернет максимальное количество элементов вместо генерации ошибки, так что вам не нужно проверять ошибки самостоятельно. Отличная причина для его использования. Более безопасный код, если дополнительные микросекунды / миллисекунды не имеют большого значения для вас при его использовании.

Автор: user7613376 Размещён: 24.04.2017 07:58

4 плюса

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

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

или же

x[-(1:5)]
Автор: Sacha Epskamp Размещён: 26.05.2011 09:55

3 плюса

Как насчет 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
Автор: Brian Davis Размещён: 17.08.2017 07:37

2 плюса

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

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
Автор: rmf Размещён: 05.08.2013 03:24

2 плюса

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

Автор: ClementWalter Размещён: 19.01.2016 11:45
Вопросы из категории :
32x32