Bagaimana cara mengakses nilai terakhir dalam vektor?


289

Misalkan saya memiliki vektor yang bersarang dalam kerangka data satu atau dua tingkat. Apakah ada cara cepat dan kotor untuk mengakses nilai terakhir, tanpa menggunakan length()fungsi? Sesuatu yang $#spesial dengan PERL ?

Jadi saya ingin sesuatu seperti:

dat$vec1$vec2[$#]

dari pada

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

1
Saya sama sekali bukan ahli R, tetapi google cepat muncul ini: < stat.ucl.ac.be/ISdidactique/Rhelp/library/pastecs/html/… > Tampaknya ada fungsi "terakhir".
Benefactual


1
MATLAB memiliki notasi "myvariable (end-k)" di mana k adalah bilangan bulat kurang dari panjang vektor yang akan mengembalikan elemen th (length (myvariable) -k). Itu akan menyenangkan untuk dimiliki di R.
EngrStudent

Jawaban:


368

Saya menggunakan tailfungsi:

tail(vector, n=1)

Yang menyenangkan tailadalah bahwa ia bekerja pada kerangka data juga, tidak seperti x[length(x)]idiom.


5
Namun x [panjang (x [, 1]),] bekerja pada kerangka data atau x [redup (x) [1],]
kpierce8

29
Perhatikan bahwa untuk frame data, panjang (x) == ncol (x) jadi itu pasti salah, dan redup (x) [1] dapat secara lebih deskriptif dituliskan nrow (x).
hadley

2
@hadley - saran kpierce8 tentang x[length(x[,1]),]tidak salah (perhatikan koma di xsubset), tapi tentu saja canggung.
jbaums

4
Harap perhatikan bahwa tolok ukur saya di bawah ini menunjukkan ini lebih lambat daripada x[length(x)]rata-rata 30 untuk vektor yang lebih besar!
Anonim

1
Tidak berfungsi jika Anda ingin menambahkan barang-barang dari vektortail(vector, n=1)-tail(vector, n=2)
Andreas Storvik Strauman

180

Untuk menjawab ini bukan dari sudut pandang estetika tetapi berorientasi kinerja, saya telah memasukkan semua saran di atas melalui tolok ukur . Lebih tepatnya, saya sudah mempertimbangkan saran

  • x[length(x)]
  • mylast(x), di mana mylastfungsi C ++ diimplementasikan melalui Rcpp,
  • tail(x, n=1)
  • dplyr::last(x)
  • x[end(x)[1]]]
  • rev(x)[1]

dan menerapkannya pada vektor acak dengan berbagai ukuran (10 ^ 3, 10 ^ 4, 10 ^ 5, 10 ^ 6, dan 10 ^ 7). Sebelum kita melihat angka-angkanya, saya pikir harus jelas bahwa segala sesuatu yang terasa lebih lambat dengan ukuran input yang lebih besar (yaitu, apa pun yang bukan O (1)) bukanlah suatu pilihan. Berikut kode yang saya gunakan:

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

Itu memberi saya

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

Ini dengan segera mengesampingkan apa pun yang melibatkan revatau endkarena mereka jelas tidak O(1)(dan ekspresi yang dihasilkan dievaluasi dengan cara yang tidak malas). taildan dplyr::lasttidak jauh dari keberadaan O(1)tetapi mereka juga jauh lebih lambat daripada mylast(x)dan x[length(x)]. Karena mylast(x)lebih lambat daripada x[length(x)]dan tidak memberikan manfaat (lebih tepatnya, itu adalah kebiasaan dan tidak menangani vektor kosong dengan anggun), saya pikir jawabannya jelas: Silakan gunakanx[length(x)] .


11
^ O (1) solusi harus menjadi satu-satunya jawaban yang dapat diterima dalam pertanyaan ini.
Kwame

2
Terima kasih telah mengatur waktu semua anon +1 itu!
Sam

1
Saya mencoba mylastR=function(x) {x[length(x)}ini lebih cepat daripada mylastdi Rcpp, tetapi satu kali lebih lambat daripada menulis x[length(x)]secara langsung
Endle_Zhenbo

115

Jika Anda mencari sesuatu yang sebagus notasi Python x [-1], saya pikir Anda kurang beruntung. Ungkapan standarnya adalah

x[length(x)]  

tetapi cukup mudah untuk menulis fungsi untuk melakukan ini:

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

Fitur yang hilang di R ini juga mengganggu saya!


3
ide bagus untuk menawarkan contoh fungsi +1
H.Latte

Perhatikan bahwa jika Anda menginginkan beberapa elemen terakhir dari vektor, bukan hanya elemen terakhir, tidak perlu melakukan sesuatu yang rumit ketika mengadaptasi solusi ini. Vektorisasi R memungkinkan Anda melakukan hal-hal bersih seperti mendapatkan empat elemen terakhir xdengan melakukan x[length(x)-0:3].
J. Mini

46

Menggabungkan ide lindelof dan Gregg Lind :

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

Bekerja pada prompt, saya biasanya menghilangkan n=, yaitu tail(x, 1).

Tidak seperti lastdari pastecspaket, headdan tail(dari utils) bekerja tidak hanya pada vektor tetapi juga pada frame data dll, dan juga dapat mengembalikan data " tanpa elemen n pertama / terakhir ", mis.

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

(Perhatikan bahwa Anda harus menggunakan headini, alih-alih tail.)


7
Harap perhatikan bahwa tolok ukur saya di bawah ini menunjukkan ini lebih lambat daripada x[length(x)]rata-rata 30 untuk vektor yang lebih besar!
Anonim

19

The dplyr paket termasuk fungsi last():

last(mtcars$mpg)
# [1] 21.4

4
Ini pada dasarnya bermuara pada x[[length(x)]]lagi.
Rich Scriven

6
Mirip di bawah tenda, tetapi dengan jawaban ini Anda tidak harus menulis fungsi Anda sendiri last()dan menyimpan fungsi itu di suatu tempat, seperti yang dilakukan beberapa orang di atas. Anda mendapatkan keterbacaan fungsi yang ditingkatkan, dengan portabilitasnya berasal dari CRAN sehingga orang lain dapat menjalankan kode.
Sam Firke

1
Dapat juga menulis sebagai mtcars$mpg %>% last, tergantung pada preferensi Anda.
Keith Hughitt

1
@RichScriven Sayangnya, ini jauh lebih lambat daripada x[[length(x)]]!
Anonim

18

Saya hanya membandingkan dua pendekatan ini pada kerangka data dengan 663.552 baris menggunakan kode berikut:

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 

dan

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 

Jadi, dengan asumsi Anda bekerja dengan vektor, mengakses posisi panjang secara signifikan lebih cepat.


3
Mengapa tidak menguji tail(strsplit(x,".",fixed=T)[[1]],1)untuk kasus ke-2? Bagi saya keuntungan utama tailadalah Anda dapat menulisnya dalam satu baris. ;)
mschilli

13

Cara lain adalah dengan mengambil elemen pertama dari vektor terbalik:

rev(dat$vect1$vec2)[1]

7
Ini akan mahal sekalipun!
Felipe Gerard

1
Harap dicatat bahwa ini adalah operasi yang biaya komputasinya linier dalam panjang input; dengan kata lain, sedangkan O (n), bukan O (1). Lihat juga tolok ukur saya di bawah ini untuk angka aktual.
Anonim

@anonymous Kecuali Anda menggunakan iterator
James

@ James Benar. Tetapi dalam kasus itu, kode Anda juga tidak akan berfungsi, bukan? Jika dengan iterator yang Anda maksud adalah apa yang disediakan oleh paket iterators, maka (1) Anda tidak dapat menggunakan [1]untuk mengakses elemen pertama dan (2) sementara Anda dapat menerapkan revke iterator, itu tidak berperilaku seperti yang diharapkan: itu hanya memperlakukan objek iterator sebagai daftar anggotanya dan membalikkan itu.
Anonim


10

Saya punya metode lain untuk menemukan elemen terakhir dalam vektor. Katakanlah vektor 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

Ini dia!


8

Tentang apa

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

1
Saya menghargai yang NROWmelakukan apa yang Anda harapkan pada banyak tipe data yang berbeda, tetapi pada dasarnya sama dengan a[length(a)]yang ingin dihindari OP. Menggunakan contoh OP dari vektor bersarang, dat$vec1$vec2[NROW(dat$vec1$vec2)]masih cukup berantakan.
Gregor Thomas

1
dapat ditulis sebagainrow
Franck Dernoncourt

2
Catatan: Tidak seperti nrow, NROWmemperlakukan vektor sebagai matriks 1-kolom.
PatrickT

3

Paket xts menyediakan lastfungsi:

library(xts)
a <- 1:100
last(a)
[1] 100
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.