vectores varias vacio seleccionar graficos graficas data crear concatenar columnas r vector equality

varias - Prueba de igualdad entre todos los elementos de un solo vector



varias graficas en r (9)

Estoy tratando de probar si todos los elementos de un vector son iguales entre sí. Las soluciones que he encontrado parecen algo indirectas, ambas implican verificar la 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 permita incluir un valor de tolerancia para evaluar la "igualdad" entre los elementos sería ideal para evitar los problemas de preguntas frecuentes 7.31 .

¿Hay una función incorporada para el tipo de prueba que he pasado por alto por completo? identical() y all.equal() comparan dos objetos R, por lo que no funcionarán aquí.

Editar 1

Aquí hay 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.


¿Por qué no simplemente usar la varianza?

var(x) == 0

Si todos los elementos de x son iguales, obtendrás una varianza de 0 .


Aquí una alternativa usando el truco min, max pero para un marco de datos. En el ejemplo estoy comparando columnas, pero el parámetro de margen desde apply puede cambiarse a 1 para filas.

valid = sum(!apply(your_dataframe, 2, function(x) diff(c(min(x), max(x)))) == 0)

Si es valid == 0 entonces todos los elementos son iguales


Como sigo volviendo a esta pregunta una y otra vez, aquí hay una solución Rcpp que generalmente será mucho más rápida que cualquiera de las soluciones R si la respuesta es realmente FALSE (porque se detendrá en el momento en que encuentra una discrepancia) y tendrá la misma velocidad que la solución R más rápida si la respuesta es TRUE . Por ejemplo, para el punto de referencia OP, system.time exactamente a 0 usando esta función.

library(inline) library(Rcpp) fast_equal = cxxfunction(signature(x = ''numeric'', y = ''numeric''), '' NumericVector var(x); double precision = as<double>(y); for (int i = 0, size = var.size(); i < size; ++i) { if (var[i] - var[0] > precision || var[0] - var[i] > precision) return Rcpp::wrap(false); } return Rcpp::wrap(true); '', plugin = ''Rcpp'') fast_equal(c(1,2,3), 0.1) #[1] FALSE fast_equal(c(1,2,3), 2) #[2] TRUE


En realidad, no necesita usar min, mean o max. Basado en la respuesta de John:

all(abs(x - x[[1]]) < tolerance)


Escribí una función específicamente para esto, que puede verificar no solo los elementos en un vector, sino que también puede verificar si todos los elementos en una lista son idénticos . Por supuesto, también maneja bien los vectores de caracteres y todos los otros tipos de vectores. También tiene un manejo de error apropiado.

all_identical <- function(x) { if (length(x) == 1L) { warning("''x'' has a length of only 1") return(TRUE) } else if (length(x) == 0L) { warning("''x'' has a length of 0") return(logical(0)) } else { TF <- vapply(1:(length(x)-1), function(n) identical(x[[n]], x[[n+1]]), logical(1)) if (all(TF)) TRUE else FALSE } }

Ahora prueba algunos ejemplos.

x <- c(1, 1, 1, NA, 1, 1, 1) all_identical(x) ## Return FALSE all_identical(x[-4]) ## Return TRUE y <- list(fac1 = factor(c("A", "B")), fac2 = factor(c("A", "B"), levels = c("B", "A")) ) all_identical(y) ## Return FALSE as fac1 and fac2 have different level order


Puede usar identical() y all.equal() comparando el primer elemento con todos los demás, barriendo efectivamente la comparación en:

R> compare <- function(v) all(sapply( as.list(v[-1]), + FUN=function(z) {identical(z, v[1])})) R> compare(x) [1] FALSE R> compare(y) [1] TRUE R>

De esta forma, puede agregar cualquier épsilon a identical() según sea necesario.


Si todos son valores numéricos, entonces si tol es su tolerancia, entonces ...

all( abs(y - mean(y)) < tol )

es la solución a tu problema

EDITAR:

Después de mirar esto y otras respuestas, y comparar algunas cosas, lo siguiente sale dos veces más rápido que la respuesta DWin.

abs(max(x) - min(x)) < tol

Esto es un poco sorprendentemente más rápido que diff(range(x)) ya que diff no debería ser muy diferente de - y abs con dos números. Solicitar el rango debería optimizar obtener el mínimo y el máximo. Tanto la diff como el range son funciones primitivas. Pero el tiempo no miente.


Utilizo este método, que compara el mínimo y el máximo, después de dividir por el medio:

# Determine if range of vector is FP 0. zero_range <- function(x, tol = .Machine$double.eps ^ 0.5) { if (length(x) == 1) return(TRUE) x <- range(x) / mean(x) isTRUE(all.equal(x[1], x[2], tolerance = tol)) }

Si estuvieras usando esto más en serio, probablemente quieras eliminar los valores faltantes antes de calcular el rango y la media.


> isTRUE(all.equal( max(y) ,min(y)) ) [1] TRUE > isTRUE(all.equal( max(x) ,min(x)) ) [1] FALSE

Otro en la misma línea:

> diff(range(x)) < .Machine$double.eps ^ 0.5 [1] FALSE > diff(range(y)) < .Machine$double.eps ^ 0.5 [1] TRUE