Estoy tratando de probar si todos los elementos de un vector son iguales entre sí. Las soluciones que he encontrado parecen algo indirectas, y ambas implican verificación length()
.
x <- c(1, 2, 3, 4, 5, 6, 1) # FALSE
y <- rep(2, times = 7) # TRUE
Con unique()
:
length(unique(x)) == 1
length(unique(y)) == 1
Con rle()
:
length(rle(x)$values) == 1
length(rle(y)$values) == 1
Una solución que me permitiera incluir un valor de tolerancia para evaluar la 'igualdad' entre elementos sería ideal para evitar problemas de la pregunta frecuente 7.31 .
¿Existe una función incorporada para el tipo de prueba que he pasado por alto por completo? identical()
y all.equal()
compare dos objetos R, para que no funcionen aquí.
Editar 1
A continuación, se muestran algunos resultados de evaluación comparativa. Usando el código:
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)
Con los resultados:
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
Entonces parece que diff(range(x)) < .Machine$double.eps ^ 0.5
es el más rápido.
system.time(for(i in 1:1e4) zero_range(x))
, de dóndex
era el OP. La solución de John es ~ 10x parax
, ~ 3x más rápida paray
y ligeramente más lenta pararunif(1e6)
.¿Por qué no simplemente usar la variación?
Si todos los elementos de
x
son iguales, obtendrá una variación de0
.fuente
length(unique(x))=1
termina siendo aproximadamente el doble de rápido, perovar
es conciso, lo cual es bueno.John test: TRUE ; DWin test: TRUE ; zero-range test: TRUE ; variance test: FALSE
que todas las demás pruebas reconocen que los valores son idénticos en R. ¿Cómo se puede usar la prueba de varianza en ese contexto?TRUE
? En el caso de la respuesta de John, verifica si la diferencia está por encima de cierto umbral. En su caso, la diferencia entre los 2 valores es muy baja, lo que podría hacer que esté por debajo del umbral que definió.Si todos son valores numéricos, entonces si tol es su tolerancia, entonces ...
es la solución a tu problema.
EDITAR:
Después de ver esta y otras respuestas, y comparar algunas cosas, lo siguiente resulta dos veces más rápido que la respuesta de DWin.
Esto es un poco sorprendentemente más rápido que
diff(range(x))
yadiff
que no debería ser muy diferente de-
yabs
con dos números. Solicitar el rango debe optimizar obteniendo el mínimo y el máximo. Ambosdiff
yrange
son funciones primitivas. Pero el momento no miente.fuente
Otro en la misma línea:
fuente
x <- seq(1, 10) / 1e10
Puede usar
identical()
yall.equal()
comparando el primer elemento con todos los demás, barriendo efectivamente la comparación a través de:De esa manera, puede agregar cualquier épsilon
identical()
según sea necesario.fuente
Solo puedes comprobar
all(v==v[1])
fuente
NA
en su vector:x <- c(1,1,NA); all(x == x[1])
devuelveNA
, noFALSE
. En tales casoslength(unique(x)) == 1
funciona.Como sigo volviendo a esta pregunta una y otra vez, aquí hay una
Rcpp
solución que generalmente será mucho más rápida que cualquiera de lasR
soluciones si la respuesta es realmenteFALSE
(porque se detendrá en el momento en que encuentre una falta de coincidencia) y tendrá la misma velocidad como la solución R más rápida si la respuesta esTRUE
. Por ejemplo, para el punto de referencia OP, marcasystem.time
exactamente 0 usando esta función.fuente
fast_equal(c(2,1,3), 1.5)
a == b
,b == c
no implica necesariamentea == c
si está haciendo comparaciones de punto flotante. Se puede dividir o bien su precisión por el número de elementos para evitar este problema, o modificar el algoritmo para calcularmin
ymax
y usando eso como una condición de parada.Escribí una función específicamente para esto, que puede verificar no solo los elementos en un vector, sino que también es capaz de verificar si todos los elementos de una lista son idénticos . Por supuesto, también maneja bien los vectores de caracteres y todos los demás tipos de vectores. También tiene un manejo de errores apropiado.
Ahora pruebe algunos ejemplos.
fuente
En realidad, no es necesario utilizar min, mean o max. Basado en la respuesta de John:
fuente
Aquí una alternativa que usa el truco mínimo, máximo pero para un marco de datos. En el ejemplo, estoy comparando columnas, pero el parámetro de margen de
apply
se puede cambiar a 1 para las filas.Si
valid == 0
entonces todos los elementos son igualesfuente