2011-11-17 13 views
15

Me gustaría comprobar si un data.frame tiene elementos no finitos.Cómo comprobar un data.frame para cualquier elemento no finito

Esto parece evaluar cada columna, volviendo FALSO para cada uno (supongo que su evaluación de la hoja.de.datos como una lista):

any(!is.finite(x)) 

No entiendo por qué esto comporta de manera diferente de lo anterior , pero funciona bien si solo está buscando NAs:

any(!is.na(x)) 

Me gustaría que la solución sea lo más eficiente posible. Me di cuenta que solo puedo hacer ...

any(!is.finite(as.matrix(x))) 
+0

La eficacia es buena, pero ... ¿tiene alguna evidencia de que la velocidad de esta prueba sea (o vaya a ser) un cuello de botella en su análisis? –

+2

Es poco probable que sea un cuello de botella. Veo esta pregunta como una oportunidad para aprender más sobre R. Me pregunto si me falta algo de técnica para evaluar los elementos en un marco de datos que no sea la técnica obvia de convertir a un tipo de datos diferente – SFun28

Respuesta

15

Si escribe methods(is.na) podrás ver que tiene un método data.frame, lo que probablemente explica por qué funciona de la forma esperada, donde is.finite no. La solución habitual sería escribir uno usted mismo, ya que es solo una línea. Algo como esto tal vez,

is.finite.data.frame <- function(obj){ 
    sapply(obj,FUN = function(x) all(is.finite(x))) 
} 
+0

Gracias por la puntero a métodos() así como a la solución! Usaría "todos" en lugar de "cualquiera" y definiría una columna finita data.frame como una columna con solo finitos – SFun28

+0

@ SFun28 Buen punto, gracias. Escribí un poco demasiado rápido. Editado para reflejar su punto. – joran

6

Asumo el error que está recibiendo es la siguiente:

> any(is.infinite(z)) 
Error in is.infinite(z) : default method not implemented for type 'list' 

Este error se debe a que los is.infinite() y los is.finite() funciones no se implementan con un método para datos .frames. La función is.na() tiene un método data.frame.

La forma de evitar esto es apply() la función de cada fila, columna o elemento en el data.frame. Aquí hay un ejemplo usando sapply() aplicar la función a cada elemento is.infinite():

x <- c(1:10, NA) 
y <- c(1:11) 
z <- data.frame(x,y) 
any(sapply(z, is.infinite)) 
## or 

any(! sapply(z, is.finite)) 
3

Una diferencia es que is.na y is.finite son diferentes tipos de funciones. is.na es un genérico y se distribuirá según la clase del argumento.

> methods("is.na") 
[1] is.na.data.frame  is.na.numeric_version is.na.POSIXlt   
[4] is.na.raster*   

    Non-visible functions are asterisked 

nota en particular de que hay una función is.na.data.frame. En cuanto a esa función:

> is.na.data.frame 
function (x) 
{ 
    y <- do.call("cbind", lapply(x, "is.na")) 
    if (.row_names_info(x) > 0L) 
     rownames(y) <- row.names(x) 
    y 
} 
<bytecode: 00000000054F40F0> 
<environment: namespace:base> 

la parte que hace el trabajo es la llamada do.call("cbind", lapply(x, "is.na")) columnas que pone juntos (cbind), que son el resultado de lapply(x, "is.na"). Correr solo esto con un ejemplo hoja.de.datos (mtcars):

> lapply(mtcars, "is.na") 
$mpg 
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 

$cyl 
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 

$disp 
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 

$hp 
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 

$drat 
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 

$wt 
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 

$qsec 
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 

$vs 
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 

$am 
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 

$gear 
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 

$carb 
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 
[25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE 

vemos que esto es sólo un cálculo por columnas, poner de nuevo juntos en un hoja.de.datos.

Compare esto con is.finite que no tiene una función específica para data.frames:

> methods("is.finite") 
no methods were found 

De hecho, se trata de un método primitivo, lo que significa que los datos están en código C, no código R.

> is.finite 
function (x) .Primitive("is.finite") 

Si usted quiere hacer un cálculo por columnas con is.finite, se puede envolver como is.na.data.frame hace.

> do.call(cbind, lapply(mtcars, is.finite)) 
     mpg cyl disp hp drat wt qsec vs am gear carb 
[1,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[2,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[3,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[4,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[5,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[6,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[7,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[8,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[9,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[10,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[11,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[12,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[13,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[14,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[15,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[16,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[17,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[18,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[19,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[20,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[21,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[22,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[23,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[24,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[25,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[26,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[27,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[28,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[29,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[30,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[31,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
[32,] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 

Este último también podría ser obtenido como

sapply(mtcars, is.finite) 

las pruebas en lo que sería más eficiente, sin embargo.

+0

gracias, Brian! Aprecio el desglose de is.na.data.frame – SFun28

4

Su solución de llamada as.matrix solo funcionará si el data.frame solo tiene columnas numéricas. De lo contrario, la matriz se convertirá típicamente en una matriz de caracteres y el resultado será falso en todas partes ...

@joran tiene un buen enfoque, pero tendrá problemas con las columnas de factores a menos que se agregue un método para factores, etc. ..

is.finite(letters[1:3])   # FALSE - OK 
is.finite(factor(letters[1:3])) # TRUE - WRONG!! 

is.finite.factor <- function(obj){ 
    logical(length(obj)) 
} 

is.finite(factor(letters[1:3])) # FALSE - OK 

Además, si desea que el cheque sea lo más rápido posible, se debe evitar sapply e ir a por vapply lugar.

d <- data.frame(matrix(runif(1e6), nrow=10), letters[1:10]) 

# @joran's method 
is.finite.data.frame <- function(obj){ 
    sapply(obj,FUN = function(x) all(is.finite(x))) 
} 

system.time(x <- is.finite(d)) # 0.42 secs 

# Using vapply instead... 
is.finite.data.frame <- function(obj) { 
    vapply(obj,FUN = function(x) all(is.finite(x)), logical(1)) 
} 

system.time(y <- is.finite(d)) # 0.20 secs 

identical(x,y) # TRUE 
+0

¡Grandes puntos sobre as.matrix, factor columns y vapply! Esta respuesta está repleta de cosas buenas. =) – SFun28

Cuestiones relacionadas