ternaria musical musica forma ejemplos bipartita binaria bach aba r matrix

ejemplos - forma musical ternaria



¿Cómo verificar eficientemente si una matriz está en forma binaria(por ejemplo, todos los 1 o 0)? (5)

Tengo una función que toma una matriz binaria de tamaño mxn (potencialmente) como entrada, y me gustaría devolver un manejo de error si la matriz contiene un número que no es 0 o 1, o es NA. ¿Cómo puedo verificar esto de manera eficiente?

Por ejemplo, al generar algunos datos para un 10 x 10:

> n=10;m=10 > mat = round(matrix(runif(m*n), m, n)) > mat [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [1,] 0 1 0 1 1 0 1 0 1 0 [2,] 0 0 0 0 0 0 0 0 0 1 [3,] 1 1 0 1 1 0 0 1 1 0 [4,] 1 1 1 1 0 1 0 0 1 1 [5,] 1 1 1 0 0 1 1 1 0 1 [6,] 1 0 1 0 0 0 0 1 0 0 [7,] 0 0 0 1 0 1 1 1 1 0 [8,] 0 0 0 1 0 1 1 1 1 1 [9,] 0 0 1 1 0 1 1 1 1 1 [10,] 1 0 1 1 0 0 0 0 1 1

siempre debe devolver que la matriz es binaria, pero cambiarla de una de las siguientes maneras:

> mat[1,1]=NA > mat[1,1]=2

Debería devolver que la matriz no es binaria.

Actualmente, he estado usando en mi función:

for(i in 1:nrow(mat)) { for(j in 1:ncol(mat)) { if(is.na(mat[i,j])|(!(mat[i,j] == 1 | mat[i,j] == 0))) { stop("Data must be only 0s, 1s") } } }

pero parece terriblemente lento e ineficiente verificar individualmente cada valor para matrices grandes. ¿Hay alguna forma inteligente y fácil de hacer esto que me falta?

Gracias


Estos son los tiempos para algunas opciones (incluidas las opciones sugeridas en otras respuestas):

n=5000;m=5000 mat = round(matrix(runif(m*n), m, n)) > system.time(stopifnot(sum(mat==0) + sum(mat==1) == length(mat))) user system elapsed 0.30 0.02 0.31 > system.time(stopifnot(all(mat %in% c(0,1)))) user system elapsed 0.58 0.06 0.63 > system.time(stopifnot(all(mat==0 | mat==1))) user system elapsed 0.77 0.03 0.80

¡Todos son bastante rápidos, considerando que es una matriz de 5000 por 5000! El más rápido de los tres parece ser:

stopifnot(sum(mat==0) + sum(mat==1) == length(mat))


Inmediatamente pensé en identical(mat,matrix(as.numeric(as.logical(mat),nr=nrow(mat)) ) )

Esto deja NA como NA por lo que si desea identificar la existencia de tal, solo necesitará una any(is.na(mat)) rápida de any(is.na(mat)) o similar.

EDITAR: contrarreloj

fun2 <- function(x) { all(x %in% 0:1) } fun1 <-function(x) {identical(as.vector(x),as.numeric(as.logical(x)))} mfoo<-matrix(sample(0:10,1e6,rep=TRUE),1e3) microbenchmark(fun1(mfoo),fun2(mfoo),is.binary.sum2(mfoo),times=10) Unit: milliseconds expr min lq median uq fun1(mfoo) 2.286941 2.809926 2.835584 2.865518 fun2(mfoo) 20.369075 20.894627 21.100528 21.226464 is.binary.sum2(mfoo) 11.394503 12.418238 12.431922 12.458436 max neval 2.920253 10 21.407777 10 28.316492 10

Y en contra de lo not... tuve que try para evitar romper la prueba.

notfun <- function(mat) try(stopifnot(sum(mat==0) + sum(mat==1) == length(mat))) microbenchmark(fun1(mfoo),notfun(mfoo),is.binary.sum2(mfoo),times=10) Error : sum(mat == 0) + sum(mat == 1) == length(mat) is not TRUE ##error repeated 10x for the 10 trials Unit: milliseconds expr min lq median uq fun1(mfoo) 4.870653 4.978414 5.057524 5.268344 notfun(mfoo) 18.149273 18.685942 18.942518 19.241856 is.binary.sum2(mfoo) 11.428713 12.145842 12.516165 12.605111 max neval 5.438111 10 34.826230 10 13.090465 10

¡Yo gano! :-)


Me gusta agregar una versión ligeramente modificada de la comparación basada en sum que es más rápida que la versión de @ JamesTrimble. Espero que todas mis suposiciones sean correctas:

is.binary.sum2 <- function(x) { identical(sum(abs(x)) - sum(x == 1), 0) }

Aquí el punto de referencia:

library(rbenchmark) n=5000 m=5000 mat = round(matrix(runif(m*n), m, n)) is.binary.sum <- function(x) { sum(x == 0) + sum(x == 1) == length(x) } is.binary.sum2 <- function(x) { identical(sum(abs(x)) - sum(x == 1), 0) } is.binary.all <- function(x) { all(x == 0 | x == 1) } is.binary.in <- function(x) { all(x %in% c(0, 1)) } benchmark(is.binary.sum(mat), is.binary.sum2(mat), is.binary.all(mat), is.binary.in(mat), order="relative", replications=10) # test replications elapsed relative user.self sys.self user.child sys.child #2 is.binary.sum2(mat) 10 4.635 1.000 3.872 0.744 0 0 #1 is.binary.sum(mat) 10 7.097 1.531 6.565 0.512 0 0 #4 is.binary.in(mat) 10 10.359 2.235 9.216 1.108 0 0 #3 is.binary.all(mat) 10 12.565 2.711 11.753 0.772 0 0


Una forma bastante eficiente (y legible ) podría ser

all(mat %in% c(0,1))

Sin embargo, como se señaló, puede no ser la más rápida, si se compara con otras soluciones.

Pero, para agregar algunos, si la eficiencia es imprescindible (por ejemplo, se realiza esta prueba muchas veces) se obtiene una gran cantidad de ganancia trabajando con integer matriz de integer (las double tienen más bytes) y se integer valores integer . Esta ganancia también podría aplicarse a otras soluciones también. Algunas pruebas con %in% siguen:

library(microbenchmark) set.seed(1) my.dim <- 1e04 n <- my.dim m <- my.dim mat <- round(matrix(runif(m*n), m, n)) int.mat <- as.integer(mat) fun1 <- function(x) { all(x %in% c(0,1)) } fun2 <- function(x) { all(x %in% 0:1) } ## why? storage.mode(0:1) ## [1] "integer" storage.mode(c(0,1)) ## [1] "double" object.size(0:1) ## 48 bytes object.size(c(0,1)) ## 56 bytes ## and considering mat and int.mat object.size(mat) ## 800000200 bytes object.size(int.mat) ## 400000040 bytes (res <- microbenchmark(fun1(mat), fun2(int.mat), times = 10, unit = "s")) ## Unit: seconds ## expr min lq median uq max neval ## fun1(mat) 3.68843 3.69325 3.70433 3.72627 3.73041 10 ## fun2(int.mat) 1.28956 1.29157 1.32934 1.34370 1.35718 10

De 3.70 a 1.32 no es tan malo :)


Tenga en cuenta que he cambiado algunas cosas para que se ejecute en octave , pero debería ser bastante similar a matlab .

Genera la matriz:

n=5000;m=5000 mat=randi([0,1],n,m);

Ahora solo hacemos algo simple, sabemos que 1*2-1 haría que el 1 igual a 1 , mientras que hace que 0 sea ​​igual a -1 . Entonces, abs hace todo igual. Para cualquier otro valor, digamos -1 , -1*2-1=-3 este no es el caso. Luego restamos 1 y deberíamos quedarnos con una matriz con solo ceros. Esto se puede verificar fácilmente en matlab / octava con any :

any(any(abs(mat*2-1)-1));

Comprobando su velocidad:

mat=randi([0,1],n,m); [t0 u0 s0]=cputime(); any(any(abs(mat+mat-1)-1)); [t1 u1 s1]=cputime(); [t1-t0 u1-u0 s1-s0] ans = 0.176772 0.127546 0.049226

En el orden total , user y hora del system .

Bastante decente en 0.18 segundos con la mayor parte en modo de usuario. Con 10.000 * 10.000 entradas todavía está por debajo de un segundo, registrando en 0.86 segundos en mi sistema.

Oh, diablos, solo ahora veo que en realidad se pide R , no matlab . Espero que a alguien le guste la comparación sin embargo.

Manejar los valores de NaN es fácil en octave / matlab con isnan(mat) , eventualmente en forma de any(any(isnan(mat))) si lo desea. Esto incluye los valores de NA . Manejar solo los valores de NA es a través de isna(mat) .