web-dev-qa-db-ja.com

ベクトルの最後のn個の要素を取得します。 length()関数を使用するよりも良い方法はありますか?

引数のために、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
> 

質問は時系列分析に関連していますが、最近のデータでのみ作業することがしばしば有用です。

71
Thomas Browne

見る ?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がコメントで述べているように、1億の値のベクトルでこれを100万回実行する必要がある場合、テールソリューションよりも高速な他の2つの可能性があります。読みやすくするために、私は尻尾を付けます。

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)
)
99
Joris Meys

ここでの速度だけに基づく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は、エラーを生成するのではなく、単純に要素の最大数を返すため、自分でエラーをチェックする必要はありません。それを使用する大きな理由。余分なマイクロ秒/ミリ秒がその使用においてあまり重要でない場合、より安全でクリーンなコード。

5
user7613376

Rでさらに2つの文字を使用して、まったく同じことを行うことができます。

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

または

x[-(1:5)]
4
Sacha Epskamp

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
3
Brian Davis

これはそれを行う関数であり、かなり高速に思えます。

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
rmf

ここに関連するものを追加します。バックエンドインデックスを持つベクトルにアクセスする、つまりtail(x, i)のようなものを書きたいが、テール全体ではなくx[length(x) - i + 1]を返すようにしたかったのです。

以下の解説に従って、2つのソリューションのベンチマークを行いました。

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
ClementWalter