J'essaie de tester si tous les éléments d'un vecteur sont égaux les uns aux autres. Les solutions que j'ai proposées semblent quelque peu détournées, toutes deux impliquant des vérifications length()
.
x <- c(1, 2, 3, 4, 5, 6, 1) # FALSE
y <- rep(2, times = 7) # TRUE
Avec unique()
:
length(unique(x)) == 1
length(unique(y)) == 1
Avec rle()
:
length(rle(x)$values) == 1
length(rle(y)$values) == 1
Une solution qui me permettrait d'inclure une valeur de tolérance pour évaluer «l'égalité» entre les éléments serait idéale pour éviter les problèmes de la FAQ 7.31 .
Existe-t-il une fonction intégrée pour le type de test que j'ai complètement négligée? identical()
et all.equal()
comparez deux objets R, afin qu'ils ne fonctionnent pas ici.
Modifier 1
Voici quelques résultats d'analyse comparative. En utilisant le code:
library(rbenchmark)
John <- function() all( abs(x - mean(x)) < .Machine$double.eps ^ 0.5 )
DWin <- function() {diff(range(x)) < .Machine$double.eps ^ 0.5}
zero_range <- function() {
if (length(x) == 1) return(TRUE)
x <- range(x) / mean(x)
isTRUE(all.equal(x[1], x[2], tolerance = .Machine$double.eps ^ 0.5))
}
x <- runif(500000);
benchmark(John(), DWin(), zero_range(),
columns=c("test", "replications", "elapsed", "relative"),
order="relative", replications = 10000)
Avec les résultats:
test replications elapsed relative
2 DWin() 10000 109.415 1.000000
3 zero_range() 10000 126.912 1.159914
1 John() 10000 208.463 1.905251
On dirait donc que diff(range(x)) < .Machine$double.eps ^ 0.5
c'est le plus rapide.
system.time(for(i in 1:1e4) zero_range(x))
, d'où venaitx
l'OP. La solution de John est ~ 10x pourx
, ~ 3x plus rapide poury
et légèrement plus lente pourrunif(1e6)
.Pourquoi ne pas simplement utiliser la variance:
Si tous les éléments de
x
sont égaux, vous obtiendrez une variance de0
.la source
length(unique(x))=1
finit par être environ deux fois plus rapide, maisvar
est laconique, ce qui est bien.John test: TRUE ; DWin test: TRUE ; zero-range test: TRUE ; variance test: FALSE
sens, tous les autres tests reconnaissent que les valeurs sont identiques dans R. Comment le test de variance peut-il être utilisé dans ce contexte?TRUE
? Dans le cas de la réponse de John, vous vérifiez si la différence est supérieure à un certain seuil. Dans votre cas, la différence entre les 2 valeurs est très faible, ce qui pourrait le conduire à être en dessous du seuil que vous avez défini.Si ce sont toutes des valeurs numériques, si tol est votre tolérance, alors ...
est la solution à votre problème.
ÉDITER:
Après avoir examiné ceci, et d'autres réponses, et comparé quelques points, ce qui suit ressort deux fois plus vite que la réponse DWin.
C'est un peu étonnamment plus rapide que
diff(range(x))
puisquediff
ne devrait pas être très différent de-
etabs
avec deux nombres. La demande de la gamme devrait optimiser l'obtention du minimum et du maximum. Les deuxdiff
etrange
sont des fonctions primitives. Mais le timing ne ment pas.la source
Un autre dans le même sens:
la source
x <- seq(1, 10) / 1e10
Vous pouvez utiliser
identical()
etall.equal()
en comparant le premier élément à tous les autres, balayant efficacement la comparaison à travers:De cette façon, vous pouvez ajouter n'importe quel epsilon au
identical()
besoin.la source
Vous pouvez simplement vérifier
all(v==v[1])
la source
NA
dans votre vecteur:x <- c(1,1,NA); all(x == x[1])
renvoieNA
, nonFALSE
. Dans de tels caslength(unique(x)) == 1
fonctionne.Puisque je reviens sans cesse sur cette question, voici une
Rcpp
solution qui sera généralement beaucoup plus rapide que n'importe laquelle desR
solutions si la réponse est réellementFALSE
(car elle s'arrêtera au moment où elle rencontrera une discordance) et aura la même vitesse comme la solution R la plus rapide si la réponse estTRUE
. Par exemple, pour le benchmark OP,system.time
horloges à exactement 0 en utilisant cette fonction.la source
fast_equal(c(2,1,3), 1.5)
a == b
,b == c
ne signifie pas nécessairementa == c
si vous faites des comparaisons à virgule flottante. Vous pouvez diviser votre précision par le nombre d'éléments pour éviter ce problème, ou de modifier l'algorithme pour calculermin
etmax
et utiliser cela comme une condition d' arrêt.J'ai écrit une fonction spécialement pour cela, qui peut vérifier non seulement les éléments d'un vecteur, mais également capable de vérifier si tous les éléments d'une liste sont identiques . Bien sûr, il gère également les vecteurs de caractères et tous les autres types de vecteurs. Il dispose également d'une gestion des erreurs appropriée.
Maintenant, essayez quelques exemples.
la source
Vous n'avez pas réellement besoin d'utiliser min, mean ou max. Basé sur la réponse de John:
la source
Voici une alternative utilisant l'astuce min, max mais pour une trame de données. Dans l'exemple, je compare des colonnes, mais le paramètre de marge de
apply
peut être changé en 1 pour les lignes.Si
valid == 0
alors tous les éléments sont les mêmesla source