ベクトルの最後の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
> 

この質問は時系列分析に関連しており、最近のデータのみを処理することがしばしば役立ちます。

回答:


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がコメントで述べているように、1億の値のベクトルでこれを百万回実行する必要がある場合に備えて、テールソリューションよりも高速な他の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)
)

しかし、スライスよりも速くはありません-テストはこれを裏付けます。
ニックバスティン

1
ニックに感謝します。ええ、Pythonのスライスはこの言語の優れた機能です。
トーマスブラウン

5
@ニック:確かに。長さが1e6で複製が1000のベクトルでは、約0.3秒遅くなります。あなたが保存されて0.3秒...と何ができるか想像して
ヨリスMeys

6
utils ::: tail.defaultの実装は、サニティチェックなしのx[seq.int(to=length(x), length.out=5)]場合よりも約10倍速いようtail()です。x[length(x)-(4:0)]それでも速いです。
マーティンモーガン

1
@Joris:内側のループでその特定の操作を10億回実行した後、私がそれらをどうするか想像できます。:-)要点は、スライスはそれほど明確ではありませんが、より最適であるため、一般的に私はそのルートに行きます。
ニックバスティン

6

Rでも、さらに2文字でまったく同じことができます。

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

または

x[-(1:5)]

ベクトルの長さがわからないが、常に最後の5つの要素が必要な場合はどうなりますか?Pythonバージョンは引き続き機能しますが、Rの例では最後の15要素が返されるため、length()を呼び出す必要がありますか?
トーマスブラウン

10
サチャ、あなたの答えは一般化していないと思います。コード例では、最後の5つを保持するのではなく、最初の5つの結果を削除します。この例では同じことですが、以下は機能しません x <- 0:20; x[-5:-1]。-これは最後の15個の要素を返します。
アンドリー

私はPythonを知りませんが、OPx[-5:]では:これは最初の5つの要素をスキップすることを意味しますか、それとも最後の5つを保持することを意味しますか?それが最初のものである場合、彼はここであなたのように間接的にあなたの長さを使用しています(そうでなければ、どの要素をスキップするかをどうやって知るのですか?)
Nick Sabbe

1
Pythonの「-」演算子は、逆方向にカウントすることを意味します。したがって、この場合は常に最後の5つの要素が返されます。
トーマスブラウン

2
ああ、そうだね、私はpythonを知らないので、最初の5をスキップすることを意味するtail と思いました。
Sacha Epskamp 2011年

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
Chris Njuguna 2018

良い点@ChrisNjuguna。ただし、長さ10のベクトルを使用すると
Brian Davis

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

ここに関連するものを追加します。私は、バックエンドインデックスを持つベクトルにアクセスしたかったのです。つまり、テール全体ではなく、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直接アクセスに比べて非常に遅いように見えます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.