it-swarm-eu.dev

Wie greife ich auf den letzten Wert eines Vektors zu?

Angenommen, ich habe einen Vektor, der in einem Datenrahmen einer oder zwei Ebenen verschachtelt ist. Gibt es eine schnelle und fehlerhafte Möglichkeit, auf den letzten Wert zuzugreifen, ohne die Funktion length() zu verwenden? Etwas ala Perls $# spezielle var?

Also ich hätte gerne etwas wie:

dat$vec1$vec2[$#]

anstatt von

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

Ich benutze die Funktion tail:

tail(vector, n=1)

Das Schöne an tail ist, dass es im Gegensatz zur x[length(x)]-Idiom auch auf Datenrahmen funktioniert.

330
lindelof

Um dies nicht aus ästhetischer, sondern aus leistungsorientierter Sicht zu beantworten, habe ich alle oben genannten Vorschläge mit einem Benchmark versehen. Um genau zu sein, habe ich die Vorschläge berücksichtigt

  • x[length(x)]
  • mylast(x), wobei mylast eine durch Rcpp implementierte C++ - Funktion ist,
  • tail(x, n=1)
  • dplyr::last(x)
  • x[end(x)[1]]]
  • rev(x)[1]

und wendete sie auf Zufallsvektoren verschiedener Größen an (10 ^ 3, 10 ^ 4, 10 ^ 5, 10 ^ 6 und 10 ^ 7). Bevor wir uns die Zahlen ansehen, sollte klar sein, dass alles, was mit größerer Eingabegröße merklich langsamer wird (dh alles, was nicht O(1)) ist), keine Option ist Der Code, den ich verwendet habe:

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

Es gibt mir

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

Dies schließt sofort alles aus, was rev oder end betrifft, da es sich eindeutig nicht um O(1) handelt (und die resultierenden Ausdrücke nicht faul ausgewertet werden). tail und dplyr::last sind nicht weit davon entfernt, O(1) zu sein, aber sie sind auch erheblich langsamer als mylast(x) und x[length(x)]. Da mylast(x) langsamer als x[length(x)] ist und keine Vorteile bietet (eher ist es benutzerdefiniert und behandelt einen leeren Vektor nicht ordnungsgemäß), denke ich, dass die Antwort klar ist: Bitte verwenden Sie x[length(x)].

143
anonymous

Wenn Sie nach etwas Schönem wie Pythons x [-1] -Notation suchen, haben Sie vermutlich kein Glück. Die Standardsprache ist

x[length(x)]  

aber es ist einfach genug, eine Funktion zu schreiben, um dies zu tun:

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

Diese fehlende Funktion in R ärgert mich auch!

104
Gregg Lind

Kombinieren von lindelof's und Gregg Lind's Ideen:

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

Wenn ich an der Eingabeaufforderung arbeite, lasse ich normalerweise das Zeichen n= Aus, d. H. tail(x, 1).

Im Gegensatz zu last aus dem pastecs -Paket arbeiten head und tail (aus utils) nicht nur mit Vektoren, sondern auch mit Datenrahmen usw . und kann auch Daten " ohne erste/letzte n Elemente " zurückgeben, z.

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

(Beachten Sie, dass Sie hierfür head anstelle von tail verwenden müssen.)

44
Florian Jenn

Ich habe diese beiden Ansätze für Datenrahmen mit 663.552 Zeilen mit folgendem Code verglichen:

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 

und

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 

Vorausgesetzt, Sie arbeiten mit Vektoren, ist der Zugriff auf die Längenposition bedeutend schneller.

17
scuerda

Das dplyr -Paket enthält eine Funktion last():

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

Ein anderer Weg ist, das erste Element des umgekehrten Vektors zu nehmen:

rev(dat$vect1$vec2)[1]
12
James

Ich habe eine andere Methode, um das letzte Element in einem Vektor zu finden. Angenommen, der Vektor ist 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

Es geht los!

9
Akash

Paket data.table enthält die Funktion last

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

Was ist mit

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

Das xts-Paket bietet eine last -Funktion:

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