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)]
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)]
.
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)]
.
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!
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
.)
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.
Le paquet dplyr inclut une fonction last()
:
last(mtcars$mpg)
# [1] 21.4
Une autre façon consiste à prendre le premier élément du vecteur inversé:
rev(dat$vect1$vec2)[1]
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à!
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
Le paquet xts fournit une fonction last
:
library(xts)
a <- 1:100
last(a)
[1] 100