Bir vektördeki son değere nasıl erişilir?


290

Bir veya iki düzeyde bir veri çerçevesinde iç içe bir vektörüm olduğunu varsayalım. length()İşlevi kullanmadan son değere erişmenin hızlı ve kirli bir yolu var mı ? Ala perl $#özel bir şey var mı?

Yani şöyle bir şey istiyorum:

dat$vec1$vec2[$#]

onun yerine

dat$vec1$vec2[length(dat$vec1$vec2)]

1
Ben kesinlikle bir R uzmanı değilim, ama hızlı bir google bu ortaya çıktı: < stat.ucl.ac.be/ISdidactique/Rhelp/library/pastecs/html/… > "Son" bir fonksiyon var gibi görünüyor.
Yararlı


1
MATLAB, "değişken (son-k)" göstergesine sahiptir, burada k, vektörün (uzunluk (değişken)) -k elemanını döndürecek olan uzunluktan daha küçük bir tamsayıdır.
R.'de

Yanıtlar:


369

Ben tailfonksiyonu kullanın :

tail(vector, n=1)

Güzel olan şey tail, x[length(x)]deyimin aksine, veri çerçeveleri üzerinde de çalışmasıdır .


5
ancak x [uzunluk (x [, 1]),] veri çerçeveleri üzerinde çalışır veya x [dim (x) [1],]
kpierce8

29
Veri çerçeveleri için, uzunluk (x) == ncol (x) kesinlikle yanlıştır ve dim (x) [1] daha açıklayıcı olarak nrow (x) olarak yazılabilir.
hadley

2
@hadley - kpierce8'in önerisi x[length(x[,1]),]yanlış değil ( xalt kümedeki virgülün not edilmesi ), ama kesinlikle garip.
jbaums

4
Aşağıdaki karşılaştırmamın bunun daha x[length(x)]büyük vektörler için ortalama 30 faktörden daha yavaş olduğunu lütfen unutmayın !
anonim

1
Vektörlerden bir şeyler eklemek istiyorsanız işe yaramaztail(vector, n=1)-tail(vector, n=2)
Andreas Storvik Strauman

181

Bunu estetik değil, performans odaklı bir bakış açısıyla cevaplamak için, yukarıdaki önerilerin tümünü bir kıyaslama ile ortaya koydum . Kesin olmak gerekirse, önerileri düşündüm

  • x[length(x)]
  • mylast(x), mylastRcpp aracılığıyla uygulanan bir C ++ işlevi nerede,
  • tail(x, n=1)
  • dplyr::last(x)
  • x[end(x)[1]]]
  • rev(x)[1]

ve bunları çeşitli boyutlarda (10 ^ 3, 10 ^ 4, 10 ^ 5, 10 ^ 6 ve 10 ^ 7) rastgele vektörlere uyguladı. Rakamlara bakmadan önce, daha büyük girdi boyutuyla (yani O (1) olmayan herhangi bir şey) fark edilir derecede yavaşlayan her şeyin bir seçenek olmadığı açık olmalıdır. İşte kullandığım kod:

Rcpp::cppFunction('double mylast(NumericVector x) { int n = x.size(); return x[n-1]; }')
options(width=100)
for (n in c(1e3,1e4,1e5,1e6,1e7)) {
  x <- runif(n);
  print(microbenchmark::microbenchmark(x[length(x)],
                                       mylast(x),
                                       tail(x, n=1),
                                       dplyr::last(x),
                                       x[end(x)[1]],
                                       rev(x)[1]))}

Bana verir

Unit: nanoseconds
           expr   min      lq     mean  median      uq   max neval
   x[length(x)]   171   291.5   388.91   337.5   390.0  3233   100
      mylast(x)  1291  1832.0  2329.11  2063.0  2276.0 19053   100
 tail(x, n = 1)  7718  9589.5 11236.27 10683.0 12149.0 32711   100
 dplyr::last(x) 16341 19049.5 22080.23 21673.0 23485.5 70047   100
   x[end(x)[1]]  7688 10434.0 13288.05 11889.5 13166.5 78536   100
      rev(x)[1]  7829  8951.5 10995.59  9883.0 10890.0 45763   100
Unit: nanoseconds
           expr   min      lq     mean  median      uq    max neval
   x[length(x)]   204   323.0   475.76   386.5   459.5   6029   100
      mylast(x)  1469  2102.5  2708.50  2462.0  2995.0   9723   100
 tail(x, n = 1)  7671  9504.5 12470.82 10986.5 12748.0  62320   100
 dplyr::last(x) 15703 19933.5 26352.66 22469.5 25356.5 126314   100
   x[end(x)[1]] 13766 18800.5 27137.17 21677.5 26207.5  95982   100
      rev(x)[1] 52785 58624.0 78640.93 60213.0 72778.0 851113   100
Unit: nanoseconds
           expr     min        lq       mean    median        uq     max neval
   x[length(x)]     214     346.0     583.40     529.5     720.0    1512   100
      mylast(x)    1393    2126.0    4872.60    4905.5    7338.0    9806   100
 tail(x, n = 1)    8343   10384.0   19558.05   18121.0   25417.0   69608   100
 dplyr::last(x)   16065   22960.0   36671.13   37212.0   48071.5   75946   100
   x[end(x)[1]]  360176  404965.5  432528.84  424798.0  450996.0  710501   100
      rev(x)[1] 1060547 1140149.0 1189297.38 1180997.5 1225849.0 1383479   100
Unit: nanoseconds
           expr     min        lq        mean    median         uq      max neval
   x[length(x)]     327     584.0     1150.75     996.5     1652.5     3974   100
      mylast(x)    2060    3128.5     7541.51    8899.0     9958.0    16175   100
 tail(x, n = 1)   10484   16936.0    30250.11   34030.0    39355.0    52689   100
 dplyr::last(x)   19133   47444.5    55280.09   61205.5    66312.5   105851   100
   x[end(x)[1]] 1110956 2298408.0  3670360.45 2334753.0  4475915.0 19235341   100
      rev(x)[1] 6536063 7969103.0 11004418.46 9973664.5 12340089.5 28447454   100
Unit: nanoseconds
           expr      min         lq         mean      median          uq       max neval
   x[length(x)]      327      722.0      1644.16      1133.5      2055.5     13724   100
      mylast(x)     1962     3727.5      9578.21      9951.5     12887.5     41773   100
 tail(x, n = 1)     9829    21038.0     36623.67     43710.0     48883.0     66289   100
 dplyr::last(x)    21832    35269.0     60523.40     63726.0     75539.5    200064   100
   x[end(x)[1]] 21008128 23004594.5  37356132.43  30006737.0  47839917.0 105430564   100
      rev(x)[1] 74317382 92985054.0 108618154.55 102328667.5 112443834.0 187925942   100

Bu, hemen dahil olan revveya endaçıkça olmadığı için O(1)(ve sonuçta ortaya çıkan ifadeler tembel olmayan bir şekilde değerlendirilir) hemen dışlar. tailve dplyr::lastuzak olmaktan değildir O(1)ama önemli ölçüde daha yavaş da konum mylast(x)ve x[length(x)]. Bundan mylast(x)daha yavaş x[length(x)]ve hiçbir fayda sağlamadığından (daha ziyade özeldir ve boş bir vektörü zarifçe işlemez), cevabın açık olduğunu düşünüyorum: Lütfen kullanınx[length(x)] .


11
^ O (1) çözümleri bu soruda kabul edilebilir tek cevap olmalıdır.
Kwame

2
Tüm bu anon +1 zamanlama için teşekkürler!
Sam

1
Denedim Rcpp'den mylastR=function(x) {x[length(x)}daha hızlı mylast, ama x[length(x)]doğrudan yazmaktan bir kez daha yavaş
Endle_Zhenbo

115

Python'un x [-1] notasyonu kadar güzel bir şey arıyorsanız, bence şansınız kalmadı. Standart deyim

x[length(x)]  

ancak bunu yapmak için bir işlev yazmak yeterince kolaydır:

last <- function(x) { return( x[length(x)] ) }

R'deki bu eksik özellik beni de kızdırıyor!


3
bir işlev örneği sunmak için güzel bir fikir +1
H.Latte

Bir vektörün sadece son öğe yerine son birkaç öğesini istiyorsanız, bu çözümü uyarlarken karmaşık bir şey yapmaya gerek olmadığını unutmayın. R'ın vectorization sen neet şeyler son dört öğelerini almak ister yapmanızı sağlar xyaparak x[length(x)-0:3].
J. Mini

46

Lindelof ve Gregg Lind'in fikirlerini birleştirmek :

last <- function(x) { tail(x, n = 1) }

İstemde çalışırken, genellikle n=, yani atlar tail(x, 1).

Aksine lastgelen pastecspaket, headve tail(adlı utilsçalışma vektörleri üzerinde değil, aynı zamanda veri çerçeveleri vs. ve aynı zamanda "veri dönebilir üzerinde değil) ilk / son n elemanları olmadan ", örneğin,

but.last <- function(x) { head(x, n = -1) }

( headBunun yerine bunu kullanmanız gerektiğini unutmayın tail.)


7
Aşağıdaki karşılaştırmamın bunun daha x[length(x)]büyük vektörler için ortalama 30 faktörden daha yavaş olduğunu lütfen unutmayın !
anonim

19

Dplyr paketi bir işlev içerir last():

last(mtcars$mpg)
# [1] 21.4

4
Bu temelde x[[length(x)]]tekrar kaynar .
Zengin Scriven

6
Kaputun altında benzer, ancak bu cevapla, kendi işlevinizi yazmak last()ve bu işlevi bir yerde saklamak zorunda değilsiniz , örneğin birkaç kişi yukarıda yaptı. Bir fonksiyonun daha iyi okunabilirliğini elde edersiniz, taşınabilirliği CRAN'dan gelir, böylece başka biri kodu çalıştırabilir.
Sam Firke

1
mtcars$mpg %>% lastTercihinize bağlı olarak da yazabilir .
Keith Hughitt

1
@RichScriven Ne yazık ki, yine de oldukça yavaş x[[length(x)]]!
anonim

18

Bu iki yaklaşımı 663.552 satırlı veri çerçevesinde aşağıdaki kodu kullanarak karşılaştırdım:

system.time(
  resultsByLevel$subject <- sapply(resultsByLevel$variable, function(x) {
    s <- strsplit(x, ".", fixed=TRUE)[[1]]
    s[length(s)]
  })
  )

 user  system elapsed 
  3.722   0.000   3.594 

ve

system.time(
  resultsByLevel$subject <- sapply(resultsByLevel$variable, function(x) {
    s <- strsplit(x, ".", fixed=TRUE)[[1]]
    tail(s, n=1)
  })
  )

   user  system elapsed 
 28.174   0.000  27.662 

Yani, vektörlerle çalıştığınızı varsayarsak, uzunluk konumuna erişmek önemli ölçüde daha hızlıdır.


3
Neden tail(strsplit(x,".",fixed=T)[[1]],1)ikinci vaka için test yapmıyorsunuz ? Bana göre en büyük avantajı tailbir satırda yazabilmeniz. ;)
mschilli

13

Başka bir yol, ters vektörün ilk elemanını almaktır:

rev(dat$vect1$vec2)[1]

7
Bu olsa pahalı olacak !
Felipe Gerard

1
Bunun, hesaplama maliyeti girişin uzunluğu boyunca doğrusal olan bir işlem olduğunu lütfen unutmayın; diğer bir deyişle, O (n) iken, O (1) değildir. Gerçek sayılar için aşağıdaki karşılaştırmamı da inceleyin.
anonim

@anonymous Bir yineleyici kullanmadığınız sürece
James

@James Right. Ama bu durumda, kodunuz da çalışmaz, değil mi? Yineleyici tarafından yineleyiciler paketi tarafından sağlanan şeyi kastediyorsanız, (1) [1]ilk öğeye erişmek için kullanamazsınız ve (2) revyineleyiciye başvurabilirken , beklendiği gibi davranmaz: sadece yineleyici nesnesini üyelerinin bir listesi ve tersine çevirir.
anonim


10

Bir vektördeki son elemanı bulmak için başka bir yöntemim var. Diyelim ki vektör a.

> a<-c(1:100,555)
> end(a)      #Gives indices of last and first positions
[1] 101   1
> a[end(a)[1]]   #Gives last element in a vector
[1] 555

İşte böyle!


8

Ne hakkında

> a <- c(1:100,555)
> a[NROW(a)]
[1] 555

1
Bunun NROWbirçok farklı veri türünde beklediğiniz şeyi yaptığını takdir ediyorum , ancak aslında a[length(a)]OP'nin kaçınmayı umduğu ile aynı . OP'nin iç içe bir vektör örneğini kullanmak dat$vec1$vec2[NROW(dat$vec1$vec2)]hala oldukça dağınık.
Gregor Thomas

1
yazılabilirnrow
Franck Dernoncourt

2
Not: Farklı olarak nrow, NROWbir vektöre 1 sütunlu matris olarak davranır.
PatrickT

3

Xts paketi bir lastişlev sağlar:

library(xts)
a <- 1:100
last(a)
[1] 100
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.