Tengo datos guardados en una base de datos postgreSQL. Estoy consultando estos datos usando Python2.7 y convirtiéndolos en un Pandas DataFrame. Sin embargo, la última columna de este marco de datos tiene un diccionario (¿o una lista?) De valores dentro de él. El DataFrame se ve así:
[1] df
Station ID Pollutants
8809 {"a": "46", "b": "3", "c": "12"}
8810 {"a": "36", "b": "5", "c": "8"}
8811 {"b": "2", "c": "7"}
8812 {"c": "11"}
8813 {"a": "82", "c": "15"}
Necesito dividir esta columna en columnas separadas para que el DataFrame se vea así:
[2] df2
Station ID a b c
8809 46 3 12
8810 36 5 8
8811 NaN 2 7
8812 NaN NaN 11
8813 82 NaN 15
El principal problema que tengo es que las listas no tienen la misma longitud. Pero todas las listas solo contienen hasta los mismos 3 valores: a, b y c. Y siempre aparecen en el mismo orden (a primero, b segundo, c tercero).
El siguiente código UTILIZADO para funcionar y devolver exactamente lo que quería (df2).
[3] df
[4] objs = [df, pandas.DataFrame(df['Pollutant Levels'].tolist()).iloc[:, :3]]
[5] df2 = pandas.concat(objs, axis=1).drop('Pollutant Levels', axis=1)
[6] print(df2)
Estaba ejecutando este código la semana pasada y estaba funcionando bien. Pero ahora mi código está roto y recibo este error de la línea [4]:
IndexError: out-of-bounds on slice (end)
No hice cambios en el código, pero ahora recibo el error. Siento que esto se debe a que mi método no es robusto o adecuado.
Cualquier sugerencia u orientación sobre cómo dividir esta columna de listas en columnas separadas sería muy apreciada.
EDITAR: Creo que los métodos .tolist () y .apply no funcionan en mi código porque es una cadena unicode, es decir:
#My data format
u{'a': '1', 'b': '2', 'c': '3'}
#and not
{u'a': '1', u'b': '2', u'c': '3'}
Los datos se importan desde la base de datos postgreSQL en este formato. ¿Alguna ayuda o ideas con este problema? ¿Hay alguna manera de convertir el Unicode?
fuente
iloc
parteiloc[:, :3]
supone que habrá 3 elementos, y tal vez los segmentos de datos más recientes solo tengan 1 o 2 (por ejemplo, no hay nadab
parecidoindex 8813
)?Respuestas:
Para convertir la cadena a un dict real, puede hacer
df['Pollutant Levels'].map(eval)
. Luego, la solución a continuación se puede usar para convertir el dict a diferentes columnas.Usando un pequeño ejemplo, puede usar
.apply(pd.Series)
:Para combinarlo con el resto del marco de datos, puede
concat
las otras columnas con el resultado anterior:Usando su código, esto también funciona si omito la
iloc
parte:fuente
pd.DataFrame(df[col].tolist())
durante mucho tiempo, nunca lo penséapply(pd.Series)
. Muy agradable.DataFrame(df['col'].tolist())
enfoque es bastante más rápido que el enfoque de aplicación!df[col].map(eval)
antes de convertirla en un DataFrameSé que la pregunta es bastante antigua, pero llegué aquí buscando respuestas. En realidad, ahora hay una manera mejor (y más rápida) de hacer esto usando
json_normalize
:Esto evita las costosas funciones de aplicación ...
fuente
.json
archivos provienen de diferentes fuentes y no siempre son las mismas columnas que están anidadas. He estado tratando de encontrar una manera de crear una lista de columnas que contengan dictos pero parece que no puede funcionarfrom pandas.io.json import json_normalize
meta_prefix
yrecord_prefix
. Sin embargo, no puedo hacer que eso funcione con mi marco de datos (el marco de datos final es correcto en mi caso, pero me gustaría aplicar los prefijos).Pruebe esto: los datos devueltos por SQL deben convertirse en un Dict. o podría ser
"Pollutant Levels"
ahoraPollutants'
fuente
La respuesta de Merlín es mejor y súper fácil, pero no necesitamos una función lambda. La evaluación del diccionario se puede ignorar de forma segura por cualquiera de las dos formas siguientes, como se ilustra a continuación:
Camino 1: dos pasos
Modo 2: los dos pasos anteriores se pueden combinar de una vez:
fuente
Recomiendo encarecidamente que el método extraiga la columna 'Contaminantes':
df_pollutants = pd.DataFrame(df['Pollutants'].values.tolist(), index=df.index)
es mucho más rápido que
df_pollutants = df['Pollutants'].apply(pd.Series)
cuando el tamaño de df es gigante.
fuente
apply
todo el marco de datos es administrado por pandas, pero cuando se trata devalues
eso solo juega con elnumpy ndarrays
que es intrínsecamente más rápido debido al hecho de que tienec
implementaciones puras .Puedes usar
join
conpop
+tolist
. El rendimiento es comparable aconcat
condrop
+tolist
, pero algunos pueden encontrar este limpiador de sintaxis:Benchmarking con otros métodos:
fuente
Una solución de línea es la siguiente:
fuente
my_df = pd.DataFrame.from_dict(my_dict, orient='index', columns=['my_col'])
.. habría analizado el dict correctamente (colocando cada clave dict en una columna df separada, y los valores clave en filas df), para que los dictos no se aplasten en una sola columna en primer lugar.
fuente
He concatenado esos pasos en un método, debe pasar solo el marco de datos y la columna que contiene el dict para expandir:
fuente
fuente