Tengo algunos pandas DataFrame con NaNs en él. Me gusta esto:
import pandas as pd import numpy as np raw_data={'A':{1:2,2:3,3:4},'B':{1:np.nan,2:44,3:np.nan}} data=pd.DataFrame(raw_data) >>> data AB 1 2 NaN 2 3 44 3 4 NaN
Ahora quiero hacer un dictado y al mismo tiempo eliminar los NaN. El resultado debería verse así:
{'A': {1: 2, 2: 3, 3: 4}, 'B': {2: 44.0}}
Pero el uso de la función pandas to_dict me da un resultado como este:
>>> data.to_dict() {'A': {1: 2, 2: 3, 3: 4}, 'B': {1: nan, 2: 44.0, 3: nan}}
Entonces, ¿cómo hacer un dictado de DataFrame y deshacerse de los NaN?
escribe una función insired por to_dict desde pandas
import pandas as pd import numpy as np from pandas import compat def to_dict_dropna(self,data): return dict((k, v.dropna().to_dict()) for k, v in compat.iteritems(data)) raw_data={'A':{1:2,2:3,3:4},'B':{1:np.nan,2:44,3:np.nan}} data=pd.DataFrame(raw_data) dict=to_dict_dropna(data)
y como resultado obtienes lo que quieres:
>>> dict {'A': {1: 2, 2: 3, 3: 4}, 'B': {2: 44.0}}
Hay muchas maneras de lograr esto. Pasé un tiempo evaluando el rendimiento en un dataframe no tan grande (70k). Aunque la respuesta de @ der_die_das_jojo es funcional, también es bastante lenta.
La respuesta sugerida por esta pregunta en realidad resulta ser 5 veces más rápida en un gran dataframe.
En mi dataframe de prueba ( df
):
Método anterior:
%time [ v.dropna().to_dict() for k,v in df.iterrows() ] CPU times: user 51.2 s, sys: 0 ns, total: 51.2 s Wall time: 50.9 s
Otro método lento:
%time df.apply(lambda x: [x.dropna()], axis=1).to_dict(orient='rows') CPU times: user 1min 8s, sys: 880 ms, total: 1min 8s Wall time: 1min 8s
El método más rápido que pude encontrar:
%time [ {k:v for k,v in m.items() if pd.notnull(v)} for m in df.to_dict(orient='rows')] CPU times: user 14.5 s, sys: 176 ms, total: 14.7 s Wall time: 14.7 s
El formato de esta salida es un diccionario orientado a filas, es posible que deba hacer ajustes si desea que el formulario esté orientado a columnas en la pregunta.
Muy interesado si alguien encuentra una respuesta aún más rápida a esta pregunta.
Puedes usar un dictado de dictado y pasar sobre las columnas.
{col:df[col].dropna().to_dict() for col in df}