web-dev-qa-db-fra.com

Obtenir les n derniers éléments d'un vecteur. Existe-t-il un meilleur moyen que d’utiliser la fonction length ()?

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.

71
Thomas Browne

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)
)
99
Joris Meys

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.

5
user7613376

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)]
4
Sacha Epskamp

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
3
Brian Davis

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
2
rmf

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

2
ClementWalter