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