2016-07-06 81 views
21

Ho dati salvati in un database PostgreSQL. Sto interrogando questi dati usando Python2.7 e trasformandolo in un DataFrame di Pandas. Tuttavia, l'ultima colonna di questo dataframe ha un dizionario (o un elenco?) Di valori al suo interno. Il dataframe assomiglia a questo:Dizionario/elenco di suddivisione all'interno di una colonna di Pandas in colonne separate

[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"} 

ho bisogno di dividere questa colonna in colonne separate in modo che il dataframe assomiglia a questo:

[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 

Il problema principale che sto avendo è che le liste non sono le stesse lunghezze Ma tutti gli elenchi contengono solo gli stessi 3 valori: a, b e c. E appaiono sempre nello stesso ordine (un primo, un secondo, un terzo).

Il seguente codice USATO per funzionare e restituire esattamente quello che volevo (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) 

Ho eseguito questo codice solo la settimana scorsa e funzionava correttamente. Ma ora il mio codice è rotto e ottengo questo errore dalla linea [4]: ​​

IndexError: out-of-bounds on slice (end) 

ho fatto nessuna modifica al codice, ma ora sto ottenendo l'errore. Sento che questo è dovuto al fatto che il mio metodo non è robusto o appropriato.

Qualsiasi suggerimento o guida su come suddividere questa colonna di elenchi in colonne separate sarebbe molto apprezzato!

EDIT: Penso che la ToList() e metodi .Applicare non funzionano sul mio codice, perché è una stringa unicode, vale a dire:

#My data format 
u{'a': '1', 'b': '2', 'c': '3'} 

#and not 
{u'a': '1', u'b': '2', u'c': '3'} 

I dati sta importando dal database PostgreSQL in questo formato . Qualsiasi aiuto o idee con questo problema? c'è un modo per convertire l'unicode?

+0

ho risposto con una soluzione un po 'diversa, ma, il codice dovrebbe realmente funzionare anche bene. Usando il mio esempio fittizio qui sotto, questo funziona usando pandas 0.18.1 se tralascio la parte 'iloc' – joris

+0

Fa parte di esso che' iloc [:,: 3] 'presuppone che ci saranno 3 voci, e forse dati più recenti le slice hanno solo 1 o 2 (ad es. non ci sono 'b' come in' index 8813')? – dwanderson

risposta

35

Per convertire la stringa in un dettato effettivo, è possibile eseguire df['Pollutant Levels'].map(eval). Successivamente, la soluzione seguente può essere utilizzata per convertire il dict in colonne diverse.


Usando un piccolo esempio, è possibile utilizzare .apply(pd.Series):

In [2]: df = pd.DataFrame({'a':[1,2,3], 'b':[{'c':1}, {'d':3}, {'c':5, 'd':6}]}) 

In [3]: df 
Out[3]: 
    a     b 
0 1   {u'c': 1} 
1 2   {u'd': 3} 
2 3 {u'c': 5, u'd': 6} 

In [4]: df['b'].apply(pd.Series) 
Out[4]: 
    c d 
0 1.0 NaN 
1 NaN 3.0 
2 5.0 6.0 

di combinarlo con il resto del dataframe, è possibile concat le altre colonne con il risultato di cui sopra:

In [7]: pd.concat([df.drop(['b'], axis=1), df['b'].apply(pd.Series)], axis=1) 
Out[7]: 
    a c d 
0 1 1.0 NaN 
1 2 NaN 3.0 
2 3 5.0 6.0 

Utilizzando il codice, questo funziona anche se lascio il iloc parte:

In [15]: pd.concat([df.drop('b', axis=1), pd.DataFrame(df['b'].tolist())], axis=1) 
Out[15]: 
    a c d 
0 1 1.0 NaN 
1 2 NaN 3.0 
2 3 5.0 6.0 
+2

Ho usato 'pd.DataFrame (df [col] .tolist())' per molto tempo, mai pensato a 'apply (pd.Series)'. Molto bella. – ayhan

+0

Ora capisco il problema. L'applicazione .apply (pd.Series) non funziona sul mio set di dati perché l'intera riga è una stringa unicode. È: u '{' a ':' 1 ',' b ':' 2 ',' c ':' 3 '} e non {u'a': '1', u'b ':' 2 ', u'c ':' 3 '} come mostrano le tue soluzioni. Quindi il codice non può dividerlo in 3 colonne riconoscibili. – llaffin

+0

@ayhan In realtà, è stato testato e l'approccio 'DataFrame (df ['col']. Tolist())' è un po 'più veloce dell'approccio apply! – joris

4

Prova questo: I dati restituiti da SQL è al trasformata in un Dict. o potrebbe essere "Pollutant Levels" è ora Pollutants'

StationID     Pollutants 
0  8809 {"a":"46","b":"3","c":"12"} 
1  8810 {"a":"36","b":"5","c":"8"} 
2  8811   {"b":"2","c":"7"} 
3  8812     {"c":"11"} 
4  8813   {"a":"82","c":"15"} 


df2["Pollutants"] = df2["Pollutants"].apply(lambda x : dict(eval(x))) 
df3 = df2["Pollutants"].apply(pd.Series) 

    a b c 
0 46 3 12 
1 36 5 8 
2 NaN 2 7 
3 NaN NaN 11 
4 82 NaN 15 


result = pd.concat([df, df3], axis=1).drop('Pollutants', axis=1) 
result 

    StationID a b c 
0  8809 46 3 12 
1  8810 36 5 8 
2  8811 NaN 2 7 
3  8812 NaN NaN 11 
4  8813 82 NaN 15 
0

in una sola riga:

df = pd.concat([df['a'], df.b.apply(pd.Series)], axis=1)`