Supposons que vous ayez une liste de valeurs
x <- list(a=c(1,2,3), b = c(2,3,4), c=c(4,5,6))
Je voudrais trouver des valeurs uniques à partir de tous les éléments de liste combinés. Jusqu'à présent, le code suivant a fait l'affaire
unique(unlist(x))
Quelqu'un connaît-il un moyen plus efficace? J'ai une liste volumineuse avec beaucoup de valeurs et j'apprécierais toute accélération.
Cette solution suggérée par Marek est la meilleure réponse au Q. original. Voir ci-dessous pour une discussion sur d'autres approches et pourquoi Marek est la plus utile.
> unique(unlist(x, use.names = FALSE))
[1] 1 2 3 4 5 6
Une solution plus rapide consiste à calculer unique()
sur les composants de votre x
d'abord, puis à faire une unique()
finale sur ces résultats. Cela ne fonctionnera que si les composants de la liste ont le même nombre de valeurs uniques, comme ils le font dans les deux exemples ci-dessous. Par exemple.:
D'abord votre version, puis ma double approche unique:
> unique(unlist(x))
[1] 1 2 3 4 5 6
> unique.default(sapply(x, unique))
[1] 1 2 3 4 5 6
Nous devons appeler unique.default
Car il existe une méthode matrix
pour unique
qui maintient une marge fixe; c'est très bien car une matrice peut être traitée comme un vecteur.
Marek, dans les commentaires de cette réponse, note que la vitesse lente de l'approche unlist
est potentiellement due au names
sur la liste. La solution de Marek consiste à utiliser l'argument use.names
Pour unlist
, ce qui, s'il est utilisé, se traduit par une solution plus rapide que la version unique double ci-dessus. Pour le simple x
du post de Roman, nous obtenons
> unique(unlist(x, use.names = FALSE))
[1] 1 2 3 4 5 6
La solution de Marek fonctionnera même lorsque le nombre d'éléments uniques diffère entre les composants.
Voici un exemple plus grand avec quelques timings des trois méthodes:
## Create a large list (1000 components of length 100 each)
DF <- as.list(data.frame(matrix(sample(1:10, 1000*1000, replace = TRUE),
ncol = 1000)))
Voici les résultats des deux approches utilisant DF
:
> ## Do the three approaches give the same result:
> all.equal(unique.default(sapply(DF, unique)), unique(unlist(DF)))
[1] TRUE
> all.equal(unique(unlist(DF, use.names = FALSE)), unique(unlist(DF)))
[1] TRUE
> ## Timing Roman's original:
> system.time(replicate(10, unique(unlist(DF))))
user system elapsed
12.884 0.077 12.966
> ## Timing double unique version:
> system.time(replicate(10, unique.default(sapply(DF, unique))))
user system elapsed
0.648 0.000 0.653
> ## timing of Marek's solution:
> system.time(replicate(10, unique(unlist(DF, use.names = FALSE))))
user system elapsed
0.510 0.000 0.512
Ce qui montre que le double unique
est beaucoup plus rapide pour appliquer unique()
aux composants individuels puis unique()
ces petits ensembles de valeurs uniques, mais cette accélération est uniquement à cause du names
sur la liste DF
. Si nous disons à unlist
de ne pas utiliser le names
, la solution de Marek est légèrement plus rapide que le double unique
pour ce problème. Comme la solution de Marek utilise correctement l'outil approprié, et c'est plus rapide que la solution de contournement, c'est la solution préférée.
Le gros problème avec l'approche double unique
est qu'il ne fonctionnera que si, comme dans les deux exemples ici, chaque composant de la liste d'entrée (DF
ou x
) a le même nombre de valeurs uniques. Dans de tels cas, sapply
simplifie le résultat en une matrice qui nous permet d'appliquer unique.default
. Si les composants de la liste d'entrée ont des nombres différents de valeurs uniques, la solution unique double échouera.