web-dev-qa-db-fra.com

Comment accéder à la dernière valeur d'un vecteur?

Supposons que j'ai un vecteur qui est imbriqué dans un cadre de données à un ou deux niveaux. Existe-t-il un moyen simple et rapide d'accéder à la dernière valeur sans utiliser la fonction length()? Quelque chose d'ala Perl $# var spécial?

Je voudrais donc quelque chose comme:

dat$vec1$vec2[$#]

au lieu de

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

J'utilise la fonction tail:

tail(vector, n=1)

Le truc sympa avec tail est que cela fonctionne aussi avec les images, contrairement à l'idiome x[length(x)].

330
lindelof

Pour répondre à cette question, non pas d'un point de vue esthétique mais axé sur les performances, j'ai présenté toutes les suggestions ci-dessus au moyen d'un repère. Pour être précis, j'ai examiné les suggestions

  • x[length(x)]
  • mylast(x), où mylast est une fonction C++ implémentée via Rcpp,
  • tail(x, n=1)
  • dplyr::last(x)
  • x[end(x)[1]]]
  • rev(x)[1]

et les a appliqués à des vecteurs aléatoires de différentes tailles (10 ^ 3, 10 ^ 4, 10 ^ 5, 10 ^ 6 et 10 ^ 7). Avant d’examiner les chiffres, je pense qu’il devrait être clair que tout ce qui est sensiblement plus lent avec une taille d’entrée plus grande (c’est-à-dire tout ce qui n’est pas O(1)) n’est pas une option. Voici le code que j'ai utilisé:

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

Ça me donne

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

Ceci exclut immédiatement tout ce qui concerne rev ou end car ils ne sont clairement pas O(1) (et les expressions résultantes sont évaluées de manière non paresseuse). tail et dplyr::last ne sont pas loin d'être O(1), mais ils sont aussi beaucoup plus lents que mylast(x) et x[length(x)]. Puisque mylast(x) est plus lent que x[length(x)] et ne procure aucun avantage (il est plutôt personnalisé et ne gère pas un vecteur vide avec élégance), je pense que la réponse est claire: veuillez utiliser x[length(x)].

143
anonymous

Si vous cherchez quelque chose d'aussi beau que la notation x [-1] de Python, je pense que vous n'avez pas de chance. L'idiome standard est

x[length(x)]  

mais il est assez facile d'écrire une fonction pour faire ceci:

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

Cette fonctionnalité manquante dans R m'agace aussi!

104
Gregg Lind

Combinaison des idées lindelof's et Gregg Lind's :

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

En travaillant à l’invite, j’ omets habituellement le n=, c’est-à-dire tail(x, 1).

Contrairement à last du package pastecs, head et tail (à partir de utils) fonctionnent non seulement sur des vecteurs, mais également sur des trames de données, etc. retourne les données " sans les premier/dernier n éléments ", par exemple.

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

(Notez que vous devez utiliser head pour cela, au lieu de tail.)

44
Florian Jenn

Je viens de comparer ces deux approches sur le cadre de données avec 663 552 lignes à l'aide du code suivant:

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 

et

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 

Donc, si vous travaillez avec des vecteurs, accéder à la position de la longueur est nettement plus rapide.

17
scuerda

Le paquet dplyr inclut une fonction last():

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

Une autre façon consiste à prendre le premier élément du vecteur inversé:

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

J'ai une autre méthode pour trouver le dernier élément d'un vecteur. Disons que le vecteur est 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

Voilà!

9
Akash

Le package data.table inclut la fonction last

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

De quoi s'agit-il

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

Le paquet xts fournit une fonction last:

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