Si, par souci d'argumentation, je veux les cinq derniers éléments d'un vecteur de 10 longueurs en Python, je peux utiliser l'opérateur "-" dans l'index de plage pour:
>>> x = range(10)
>>> x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> x[-5:]
[5, 6, 7, 8, 9]
>>>
Quelle est la meilleure façon de faire cela en R? Y at-il un moyen plus propre que ma technique actuelle qui consiste à utiliser la fonction length ()?
> x <- 0:9
> x
[1] 0 1 2 3 4 5 6 7 8 9
> x[(length(x) - 4):length(x)]
[1] 5 6 7 8 9
>
La question est liée à l’analyse des séries chronologiques où il est souvent utile de ne travailler que sur des données récentes.
voir ?tail
et ?head
pour certaines fonctions pratiques:
> x <- 1:10
> tail(x,5)
[1] 6 7 8 9 10
Aux fins de l'argumentation: tout, à l'exception des cinq derniers éléments, serait:
> head(x,n=-5)
[1] 1 2 3 4 5
Comme @Martin Morgan le dit dans les commentaires, il existe deux autres possibilités qui sont plus rapides que la solution de queue, au cas où vous devriez l'exécuter un million de fois sur un vecteur de 100 millions de valeurs. Pour la lisibilité, j'irais avec la queue.
test elapsed relative
tail(x, 5) 38.70 5.724852
x[length(x) - (4:0)] 6.76 1.000000
x[seq.int(to = length(x), length.out = 5)] 7.53 1.113905
code de benchmarking:
require(rbenchmark)
x <- 1:1e8
do.call(
benchmark,
c(list(
expression(tail(x,5)),
expression(x[seq.int(to=length(x), length.out=5)]),
expression(x[length(x)-(4:0)])
), replications=1e6)
)
La désapprobation de tail
ici basée sur la vitesse ne semble pas vraiment insister sur le fait qu'une partie de la vitesse plus lente provient du fait que la queue est plus sûre, si vous n'êtes pas sûr que la longueur de x dépassera n
, le nombre d'éléments que vous souhaitez sous-définir:
x <- 1:10
tail(x, 20)
# [1] 1 2 3 4 5 6 7 8 9 10
x[length(x) - (0:19)]
#Error in x[length(x) - (0:19)] :
# only 0's may be mixed with negative subscripts
Tail renverra simplement le nombre maximal d'éléments au lieu de générer une erreur. Vous n'avez donc pas besoin de vérifier vous-même. Une bonne raison de l'utiliser. Code de nettoyage plus sûr, si l'utilisation de microsecondes/millisecondes supplémentaires n'a pas beaucoup d'importance.
Vous pouvez faire exactement la même chose en R avec deux autres personnages:
x <- 0:9
x[-5:-1]
[1] 5 6 7 8 9
ou
x[-(1:5)]
Que diriez-vous de rev(x)[1:5]
?
x<-1:10
system.time(replicate(10e6,tail(x,5)))
user system elapsed
138.85 0.26 139.28
system.time(replicate(10e6,rev(x)[1:5]))
user system elapsed
61.97 0.25 62.23
Voici une fonction pour le faire et semble assez rapide.
endv<-function(vec,val)
{
if(val>length(vec))
{
stop("Length of value greater than length of vector")
}else
{
vec[((length(vec)-val)+1):length(vec)]
}
}
USAGE:
test<-c(0,1,1,0,0,1,1,NA,1,1)
endv(test,5)
endv(LETTERS,5)
RÉFÉRENCE:
test replications elapsed relative
1 expression(tail(x, 5)) 100000 5.24 6.469
2 expression(x[seq.int(to = length(x), length.out = 5)]) 100000 0.98 1.210
3 expression(x[length(x) - (4:0)]) 100000 0.81 1.000
4 expression(endv(x, 5)) 100000 1.37 1.691
Je viens d'ajouter ici quelque chose de lié. Je voulais accéder à un vecteur avec des index backend, c’est-à-dire écrire quelque chose comme tail(x, i)
mais renvoyer x[length(x) - i + 1]
et non la queue entière.
Après commentaires, j'ai comparé deux solutions:
accessRevTail <- function(x, n) {
tail(x,n)[1]
}
accessRevLen <- function(x, n) {
x[length(x) - n + 1]
}
microbenchmark::microbenchmark(accessRevLen(1:100, 87), accessRevTail(1:100, 87))
Unit: microseconds
expr min lq mean median uq max neval
accessRevLen(1:100, 87) 1.860 2.3775 2.84976 2.803 3.2740 6.755 100
accessRevTail(1:100, 87) 22.214 23.5295 28.54027 25.112 28.4705 110.833 100
Il apparaît donc dans ce cas que même pour les petits vecteurs, tail
est très lent par rapport à l'accès direct