Làm thế nào để truy cập giá trị cuối cùng trong một vectơ?


289

Giả sử tôi có một vectơ được lồng trong một khung dữ liệu một hoặc hai cấp. Có cách nào nhanh chóng và bẩn thỉu để truy cập giá trị cuối cùng mà không cần sử dụng length()chức năng không? Một cái gì đó $#đặc biệt của ala PERL ?

Vì vậy, tôi muốn một cái gì đó như:

dat$vec1$vec2[$#]

thay vì

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

1
Tôi không có nghĩa là một chuyên gia R, nhưng một google nhanh chóng đã bật lên điều này: < stat.ucl.ac.be/ISdidactique/Rhelp/l Library / pastecs / html / bit > Có vẻ như là một chức năng "cuối cùng".
lợi vào


1
MATLAB có ký hiệu "myvariable (end-k)" trong đó k là số nguyên nhỏ hơn độ dài của vectơ sẽ trả về phần tử thứ (chiều dài (myvariable) -k). Thật tuyệt khi có ở R.
EngrStudent

Câu trả lời:


368

Tôi sử dụng tailchức năng:

tail(vector, n=1)

Điều tuyệt vời taillà nó cũng hoạt động trên dataframes, không giống như x[length(x)]thành ngữ.


5
tuy nhiên x [length (x [, 1]),] hoạt động trên dataframes hoặc x [dim (x) [1],]
kpierce8

29
Lưu ý rằng đối với các khung dữ liệu, độ dài (x) == ncol (x) vì vậy điều đó chắc chắn sai và dim (x) [1] có thể được mô tả nhiều hơn bằng cách viết nrow (x).
hadley

2
@hadley - Đề xuất của kpierce8 x[length(x[,1]),]không sai (lưu ý dấu phẩy trong xtập hợp con), nhưng chắc chắn là rất khó xử.
jbaums

4
Xin lưu ý rằng điểm chuẩn của tôi dưới đây cho thấy điều này chậm hơn so với x[length(x)]hệ số trung bình là 30 đối với các vectơ lớn hơn!
ẩn danh

1
Không hoạt động nếu bạn muốn thêm nội dung từ vectơtail(vector, n=1)-tail(vector, n=2)
Andreas Storvik Strauman

179

Để trả lời điều này không phải từ quan điểm thẩm mỹ nhưng định hướng hiệu suất, tôi đã đưa tất cả các đề xuất trên thông qua một điểm chuẩn . Nói chính xác, tôi đã xem xét các đề xuất

  • x[length(x)]
  • mylast(x), mylastchức năng C ++ được triển khai ở đâu thông qua Rcpp,
  • tail(x, n=1)
  • dplyr::last(x)
  • x[end(x)[1]]]
  • rev(x)[1]

và áp dụng chúng cho các vectơ ngẫu nhiên có kích thước khác nhau (10 ^ 3, 10 ^ 4, 10 ^ 5, 10 ^ 6 và 10 ^ 7). Trước khi chúng tôi xem xét các con số, tôi nghĩ rằng rõ ràng rằng bất cứ điều gì trở nên chậm hơn đáng kể với kích thước đầu vào lớn hơn (nghĩa là, bất cứ điều gì không phải là O (1)) không phải là một lựa chọn. Đây là mã mà tôi đã sử dụng:

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

Nó đưa cho tôi

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

Điều này ngay lập tức loại trừ bất cứ điều gì liên quan revhoặc endvì chúng rõ ràng là không O(1)(và các biểu thức kết quả được đánh giá theo kiểu không lười biếng). taildplyr::lastkhông xa O(1)nhưng họ cũng chậm hơn đáng kể so với mylast(x)x[length(x)]. Vì mylast(x)chậm hơn x[length(x)]và không cung cấp lợi ích (thay vào đó, nó tùy chỉnh và không xử lý một vectơ trống một cách duyên dáng), tôi nghĩ rằng câu trả lời là rõ ràng: Vui lòng sử dụngx[length(x)] .


11
^ O (1) giải pháp nên là câu trả lời duy nhất được chấp nhận trong câu hỏi này.
Kwame

2
Cảm ơn vì đã định thời gian cho tất cả những người đó +1!
Sam

1
Tôi đã thử mylastR=function(x) {x[length(x)}Nó nhanh hơn mylasttrong Rcpp, nhưng chậm hơn một lần so với viết x[length(x)]trực tiếp
Endle_Zhenbo

115

Nếu bạn đang tìm kiếm thứ gì đó hay như ký hiệu x [-1] của Python, tôi nghĩ bạn đã hết may mắn. Thành ngữ chuẩn là

x[length(x)]  

nhưng nó đủ dễ để viết một hàm để làm điều này:

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

Tính năng thiếu này trong R làm phiền tôi quá!


3
ý tưởng tuyệt vời để cung cấp một ví dụ chức năng +1
H.Latte

Xin lưu ý rằng nếu bạn muốn một vài phần tử cuối cùng của vectơ thay vì chỉ phần tử cuối cùng, không cần phải làm gì phức tạp khi điều chỉnh giải pháp này. Vectơ hóa của R cho phép bạn thực hiện những việc cần thiết như có được bốn yếu tố cuối cùng xbằng cách thực hiện x[length(x)-0:3].
J. Mini

46

Kết hợp các ý tưởng của lindelofGregg Lind :

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

Làm việc tại dấu nhắc, tôi thường bỏ qua n=, tức là tail(x, 1).

Không giống như lasttừ pastecsgói headtail(từ utils) hoạt động không chỉ trên các vectơ mà còn trên các khung dữ liệu, v.v. và cũng có thể trả về dữ liệu " không có phần tử n đầu tiên / cuối ", vd

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

(Lưu ý rằng bạn phải sử dụng headcho việc này, thay vì tail.)


7
Xin lưu ý rằng điểm chuẩn của tôi dưới đây cho thấy điều này chậm hơn so với x[length(x)]hệ số trung bình là 30 đối với các vectơ lớn hơn!
ẩn danh

19

Các dplyr gói bao gồm một chức năng last():

last(mtcars$mpg)
# [1] 21.4

4
Điều này về cơ bản sôi xuống x[[length(x)]]một lần nữa.
Rich Scriven

6
Tương tự như vậy, nhưng với câu trả lời này, bạn không phải viết chức năng của riêng mình last()và lưu trữ chức năng đó ở đâu đó, giống như nhiều người đã làm ở trên. Bạn có thể cải thiện khả năng đọc của một chức năng, với tính di động của nó đến từ CRAN để người khác có thể chạy mã.
Sam Firke

1
Cũng có thể viết như mtcars$mpg %>% last, tùy thuộc vào sở thích của bạn.
Keith Hughitt

1
@RichScriven Thật không may x[[length(x)]], mặc dù vậy , nó chậm hơn đáng kể !
ẩn danh

18

Tôi vừa điểm chuẩn hai cách tiếp cận này trên khung dữ liệu với 663,552 hàng sử dụng mã sau:

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 

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 

Vì vậy, giả sử bạn đang làm việc với các vectơ, truy cập vị trí độ dài nhanh hơn đáng kể.


3
Tại sao không thử nghiệm tail(strsplit(x,".",fixed=T)[[1]],1)cho trường hợp thứ 2? Đối với tôi, lợi thế chính của tailnó là bạn có thể viết nó thành một dòng. ;)
mschilli

13

Một cách khác là lấy phần tử đầu tiên của vectơ đảo ngược:

rev(dat$vect1$vec2)[1]

7
Điều này sẽ đắt tiền mặc dù!
Felipe Gerard

1
Xin lưu ý rằng đây là một hoạt động có chi phí tính toán là tuyến tính theo chiều dài của đầu vào; nói cách khác, trong khi O (n), nó không phải là O (1). Xem thêm điểm chuẩn của tôi dưới đây để biết con số thực tế.
ẩn danh

@anonymous Trừ khi bạn sử dụng một trình vòng lặp
James

@James Đúng. Nhưng trong trường hợp đó, mã của bạn cũng sẽ không hoạt động, phải không? Nếu bởi iterator, bạn có nghĩa là những gì được cung cấp bởi gói iterators, thì (1) bạn không thể sử dụng [1]để truy cập phần tử đầu tiên và (2) trong khi bạn có thể áp dụng revcho một iterator, nó không hoạt động như mong đợi: nó chỉ xử lý đối tượng iterator như một danh sách các thành viên của nó và đảo ngược điều đó.
nặc danh


10

Tôi có một phương pháp khác để tìm phần tử cuối cùng trong một vectơ. Nói vectơ là 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

Có bạn đi!


8

Những gì về

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

1
Tôi đánh giá cao điều đó NROWsẽ xảy ra với những gì bạn mong đợi ở nhiều loại dữ liệu khác nhau, nhưng về cơ bản thì giống như a[length(a)]OP đang hy vọng tránh. Sử dụng ví dụ của OP về một vectơ lồng nhau, dat$vec1$vec2[NROW(dat$vec1$vec2)]vẫn còn khá lộn xộn.
Gregor Thomas

1
có thể được viết lànrow
Franck Dernoncourt 17/07/17

2
Lưu ý: Không giống như nrow, NROWcoi vectơ là ma trận 1 cột.
PatrickT

3

Gói xts cung cấp một lastchức năng:

library(xts)
a <- 1:100
last(a)
[1] 100
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.