python pandas missing-data

python - La mejor manera de contar el número de filas con valores faltantes en un marco de datos de pandas



missing-data (7)

Actualmente se me ocurrieron algunas soluciones para contar el número de valores faltantes en un DataFrame pandas. Esos son bastante feos y me pregunto si hay una mejor manera de hacerlo.

Vamos a crear un ejemplo de DataFrame :

from numpy.random import randn df = pd.DataFrame(randn(5, 3), index=[''a'', ''c'', ''e'', ''f'', ''h''], columns=[''one'', ''two'', ''three'']) df = df.reindex([''a'', ''b'', ''c'', ''d'', ''e'', ''f'', ''g'', ''h''])

Lo que tengo actualmente es

a) Recuento de celdas con valores faltantes:

>>> sum(df.isnull().values.ravel()) 9

b) Contando filas que tienen valores faltantes en algún lugar:

>>> sum([True for idx,row in df.iterrows() if any(row.isnull())]) 3


¿Qué pasa con numpy.count_nonzero :

np.count_nonzero(df.isnull().values) np.count_nonzero(df.isnull()) # also works

count_nonzero es bastante rápido. Sin embargo, construí un marco de datos a partir de una matriz (1000,1000), inserté valores de 100 nan al azar en diferentes posiciones y medí los tiempos de las distintas respuestas en iPython:

%timeit np.count_nonzero(df.isnull().values) 1000 loops, best of 3: 1.89 ms per loop %timeit df.isnull().values.ravel().sum() 100 loops, best of 3: 3.15 ms per loop %timeit df.isnull().sum().sum() 100 loops, best of 3: 15.7 ms per loop

No es una gran mejora de tiempo sobre los OPs originales, pero posiblemente menos confuso en el código, su decisión. Realmente no hay ninguna diferencia en el tiempo de ejecución entre los dos métodos count_nonzero (con y sin .values ).


Creo que si solo quieres ver el resultado, hay una función pandas pandas.DataFrame.count .

Así que volviendo a este tema, usando df.count(axis=1) , y u obtendrá el resultado como este:

a 3 b 0 c 3 d 0 e 3 f 3 g 0 h 3 dtype: int64

Le dirá cuántos parámetros no NaN en cada fila. Mientras tanto, -(df.count(axis=1) - df.shape[1]) indica

a 0 b 3 c 0 d 3 e 0 f 0 g 3 h 0 dtype: int64


Para el segundo conteo, creo que solo reste el número de filas del número de filas devueltas desde dropna :

In [14]: from numpy.random import randn df = pd.DataFrame(randn(5, 3), index=[''a'', ''c'', ''e'', ''f'', ''h''], columns=[''one'', ''two'', ''three'']) df = df.reindex([''a'', ''b'', ''c'', ''d'', ''e'', ''f'', ''g'', ''h'']) df Out[14]: one two three a -0.209453 -0.881878 3.146375 b NaN NaN NaN c 0.049383 -0.698410 -0.482013 d NaN NaN NaN e -0.140198 -1.285411 0.547451 f -0.219877 0.022055 -2.116037 g NaN NaN NaN h -0.224695 -0.025628 -0.703680 In [18]: df.shape[0] - df.dropna().shape[0] Out[18]: 3

El primero podría lograrse utilizando los métodos integrados:

In [30]: df.isnull().values.ravel().sum() Out[30]: 9

Tiempos

In [34]: %timeit sum([True for idx,row in df.iterrows() if any(row.isnull())]) %timeit df.shape[0] - df.dropna().shape[0] %timeit sum(map(any, df.apply(pd.isnull))) 1000 loops, best of 3: 1.55 ms per loop 1000 loops, best of 3: 1.11 ms per loop 1000 loops, best of 3: 1.82 ms per loop In [33]: %timeit sum(df.isnull().values.ravel()) %timeit df.isnull().values.ravel().sum() %timeit df.isnull().sum().sum() 1000 loops, best of 3: 215 µs per loop 1000 loops, best of 3: 210 µs per loop 1000 loops, best of 3: 605 µs per loop

Así que mis alternativas son un poco más rápidas para un df de este tamaño.

Actualizar

Así que para un df con 80,000 filas obtengo lo siguiente:

In [39]: %timeit sum([True for idx,row in df.iterrows() if any(row.isnull())]) %timeit df.shape[0] - df.dropna().shape[0] %timeit sum(map(any, df.apply(pd.isnull))) %timeit np.count_nonzero(df.isnull()) 1 loops, best of 3: 9.33 s per loop 100 loops, best of 3: 6.61 ms per loop 100 loops, best of 3: 3.84 ms per loop 1000 loops, best of 3: 395 µs per loop In [40]: %timeit sum(df.isnull().values.ravel()) %timeit df.isnull().values.ravel().sum() %timeit df.isnull().sum().sum() %timeit np.count_nonzero(df.isnull().values.ravel()) 1000 loops, best of 3: 675 µs per loop 1000 loops, best of 3: 679 µs per loop 100 loops, best of 3: 6.56 ms per loop 1000 loops, best of 3: 368 µs per loop

En realidad np.count_nonzero gana este manos abajo.


Tantas respuestas erróneas aquí. OP solicitó el número de filas con valores nulos, no columnas.

Aquí hay un mejor ejemplo:

from numpy.random import randn df = pd.DataFrame(randn(5, 3), index=[''a'', ''c'', ''e'', ''f'', ''h''],columns=[''one'',''two'', ''three'']) df = df.reindex([''a'', ''b'', ''c'', ''d'', ''e'', ''f'', ''g'', ''h'',''asdf'']) print(df)

`Ahora hay obviamente 4 filas con valores nulos.

one two three a -0.571617 0.952227 0.030825 b NaN NaN NaN c 0.627611 -0.462141 1.047515 d NaN NaN NaN e 0.043763 1.351700 1.480442 f 0.630803 0.931862 1.500602 g NaN NaN NaN h 0.729103 -1.198237 -0.207602 asdf NaN NaN NaN

Obtendría la respuesta como 3 (número de columnas con NaN) si usara algunas de las respuestas aquí. La respuesta de Fuentes funciona.

Así es como lo conseguí:

df.isnull().any(axis=1).sum() #4 timeit df.isnull().any(axis=1).sum() #10000 loops, best of 3: 193 µs per loop

''Fuentes'':

sum(df.apply(lambda x: sum(x.isnull().values), axis = 1)>0) #4 timeit sum(df.apply(lambda x: sum(x.isnull().values), axis = 1)>0) #1000 loops, best of 3: 677 µs per loop


Total faltante:

df.isnull().sum().sum()

Filas con faltantes:

sum(map(any, df.isnull()))


Un enfoque simple para contar los valores faltantes en las filas o en las columnas

df.apply(lambda x: sum(x.isnull().values), axis = 0) # For columns df.apply(lambda x: sum(x.isnull().values), axis = 1) # For rows

Número de filas con al menos un valor perdido:

sum(df.apply(lambda x: sum(x.isnull().values), axis = 1)>0)


sum(df.count(axis=1) < len(df.columns)) , el número de filas que tienen menos no nulos que columnas.

Por ejemplo, el siguiente marco de datos tiene dos filas con valores perdidos.

>>> df = pd.DataFrame({"a":[1, None, 3], "b":[4, 5, None]}) >>> df a b 0 1 4 1 NaN 5 2 3 NaN >>> df.count(axis=1) 0 2 1 1 2 1 dtype: int64 >>> df.count(axis=1) < len(df.columns) 0 False 1 True 2 True dtype: bool >>> sum(df.count(axis=1) < len(df.columns)) 2