it-swarm-vi.tech

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

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 chức năng length() không? Một cái gì đó ala Perl's $# var đặc biệt?

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)]
248
user14008

Tôi sử dụng chức năng tail():

tail(vector, n=1)

Điều thú vị với tail() là nó cũng hoạt động trên các datafram, không giống như thành ngữ x[length(x)].

317
lindelof

Để 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 đã đặt tất cả các đề xuất trên thông qua điểm chuẩn. Nói chính xác, tôi đã xem xét các đề xuất

  • x[length(x)]
  • mylast(x), trong đó mylast là một hàm C++ được triển khai 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õ ràng rằng mọi thứ trở nên chậm hơn rõ rệt với kích thước đầu vào lớn hơn (tức là, bất cứ thứ gì không phải là O(1)) không phải là một tùy 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 đến rev hoặc end vì rõ ràng chúng không phải là 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::last không xa O(1) nhưng chúng 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 nào (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ụng x[length(x)].

130
anonymous

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á!

100
Gregg Lind

Kết hợp các ý tưởng của lindelof và Gregg Lind:

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

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

Không giống như last từ gói pastecs, headtail (từ utils) không chỉ hoạt động trên các vectơ mà còn trên các khung dữ liệu, v.v.

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

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

43
Florian Jenn

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 vectơ, truy cập vị trí độ dài nhanh hơn đáng kể.

17
scuerda

Gói dplyr bao gồm một hàm last():

last(mtcars$mpg)
# [1] 21.4
16
Sam Firke

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]
12
James

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 rằng 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!

9
Akash

Những gì về

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

Gói data.table bao gồm hàm last

library(data.table)
last(c(1:10))
# [1] 10
7

Gói xts cung cấp hàm last:

library(xts)
a <- 1:100
last(a)
[1] 100
2
smoff