벡터의 마지막 n 개 요소를 가져옵니다. length () 함수를 사용하는 것보다 더 좋은 방법이 있습니까?


84

인수를 위해 Python에서 길이가 10 인 벡터의 마지막 5 개 요소를 원하면 범위 인덱스에서 "-"연산자를 사용하여 다음과 같이 할 수 있습니다.

>>> 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
> 

질문은 최근 데이터에 대해서만 작업하는 것이 유용한 시계열 분석 btw와 관련이 있습니다.

답변:


120

참조 ?tail?head몇 가지 편리한 기능 :

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

인수를 위해 마지막 5 개 요소를 제외한 모든 것은 다음과 같습니다.

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

@Martin Morgan이 의견에서 말했듯이 꼬리 솔루션보다 빠른 두 가지 다른 가능성이 있습니다. 가독성을 위해 꼬리를 사용합니다.

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)
)

그러나 슬라이싱보다 빠르지는 않습니다. 테스트를 통해 확인할 수 있습니다.
Nick Bastin

1
감사합니다 닉 흥미 롭습니다. 네, 파이썬 슬라이싱은 언어의 좋은 기능입니다.
Thomas Browne

5
@Nick : 그렇습니다. 길이가 1e6이고 복제가 1000 번인 벡터에서는 약 0.3 초 ​​더 느립니다. 절약 한 0.3 초로 무엇을 할 수 있는지 상상해보세요 ...
Joris Meys

6
utils ::: tail.default의 구현은 온 전성 검사가없는 x[seq.int(to=length(x), length.out=5)]것보다 약 10 배 더 빠른 것 같습니다 tail(). x[length(x)-(4:0)]여전히 더 빠릅니다.
Martin Morgan

1
@Joris : 내부 루프에서 특정 작업을 10 억 번 실행 한 후에 어떤 작업을 수행할지 상상할 수 있습니다. :-) 요점은 슬라이싱이 덜 명확하지는 않지만 더 최적화되어 있으므로 일반적으로 저는 그 길을 갈 것입니다.
Nick Bastin

6

두 개의 문자를 더 사용하여 R에서도 똑같은 일을 할 수 있습니다.

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

또는

x[-(1:5)]

Vector의 길이를 모르지만 항상 마지막 5 개 요소를 원하면 어떻게해야합니까? 파이썬 버전은 여전히 ​​작동하지만 R 예제는 마지막 15 개 요소를 반환하므로 여전히 length ()를 호출해야합니까?
Thomas Browne

10
Sacha, 나는 당신의 대답이 일반화되지 않는다고 생각합니다. 코드 예제가하는 일은 마지막 5 개를 유지하는 대신 처음 5 개 결과를 삭제하는 것입니다. 이 예제에서는 동일하지만 다음은 작동하지 않습니다 x <- 0:20; x[-5:-1].-마지막 15 개 요소를 반환합니다.
Andrie

나는 파이썬을 모르지만 OP에서 x[-5:]: 이것은 처음 5 개 요소를 건너 뛰거나 마지막 5 개를 유지한다는 것을 의미합니까? 첫 번째는 경우처럼, 그는 간접적으로 (? 그렇지 않으면, 당신은 건너 뛸 수있는 요소 아는 방법) 여기, 당신의 길이를 사용
닉 Sabbe

1
파이썬에서 "-"연산자는 역으로 세는 것을 의미합니다. 따라서이 경우 항상 마지막 5 개 요소를 반환합니다.
Thomas Browne

2
아 맞다, 나는 파이썬을 모르고 그것이 처음 5를 건너 뛰는 것을 의미한다고 가정했다 tail .
Sacha Epskamp

6

의 승인 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은 오류를 생성하는 대신 최대 요소 수를 반환하므로 직접 오류를 검사 할 필요가 없습니다. 그것을 사용하는 큰 이유. 추가 마이크로 초 / 밀리 초가 사용하는 데별로 중요하지 않은 경우 더 안전한 깔끔한 코드입니다.


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

늦은 댓글. 벡터를 반전하는 데 걸리는 처리 시간이 긴 벡터에 비해 너무 큽니다. 때 타이밍 시도x <- 1:10e6
크리스 Njuguna

@ChrisNjuguna 좋은 포인트. 길이 10의 벡터 :하지만 사용하여 좋은 작품
브라이언 데이비스

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

2

여기에 관련 내용을 추가합니다. 나는 백엔드 지수와 벡터 같은 예을 writting 뭔가에 액세스 싶었다 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직접 액세스에 비해 매우 느립니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.