2016-07-06 19 views
21

Ich habe Daten in einer PostgreSQL-Datenbank gespeichert. Ich frage diese Daten mit Python2.7 und verwandle sie in einen Pandas DataFrame. Die letzte Spalte dieses Datenrahmens enthält jedoch ein Verzeichnis (oder eine Liste?) Von Werten. Die Datenrahmen sieht wie folgt aus:Wörterbuch/Liste in einer Pandas-Spalte in separate Spalten aufteilen

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

Ich brauche diese Spalte in separaten Spalten aufgeteilt, so dass die Datenrahmen wie folgt aussieht:

[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 

Das Hauptproblem ist, dass ich mit, dass die Listen nicht die gleichen Längen. Alle Listen enthalten jedoch nur die gleichen drei Werte: a, b und c. Und sie erscheinen immer in der gleichen Reihenfolge (eine erste, eine zweite, eine dritte).

Der folgende Code verwendet, um zu arbeiten und genau das zurückzugeben, was ich wollte (df2).

Ich habe diesen Code nur letzte Woche ausgeführt und es funktionierte gut. Aber jetzt ist mein Code gebrochen und ich bekomme diese Fehlermeldung aus der Zeile [4]: ​​

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

Ich habe keine Änderungen an den Code aber bin jetzt die Fehler. Ich denke, das liegt daran, dass meine Methode nicht robust oder korrekt ist.

Alle Vorschläge oder Hinweise zum Aufteilen dieser Spalte von Listen in separate Spalten wäre super geschätzt!

EDIT: Ich denke, die .ToList() und .apply Methoden basieren auf meinen Code nicht funktioniert, weil es eine Unicode-String ist, das heißt:

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

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

Die Daten werden in diesem Format von der PostgreSQL-Datenbank importieren . Irgendwelche Hilfe oder Ideen mit diesem Problem? Gibt es eine Möglichkeit, den Unicode zu konvertieren?

+0

ich mit einer etwas anderen Lösung beantwortet, aber sollte Ihr Code tatsächlich funktioniert auch ganz gut. Ich benutze mein Dummy-Beispiel unten, das funktioniert mit Pandas 0.18.1, wenn ich den "iloc" -Teil weglasse – joris

+0

Es ist ein Teil davon, dass das 'iloc [:, 3]' annimmt, dass es 3 Elemente und vielleicht neuere Daten geben wird Slices haben nur 1 oder 2 (zB gibt es kein 'b' wie in' Index 8813')? – dwanderson

Antwort

35

Um die Zeichenfolge in ein aktuelles Dict zu konvertieren, können Sie df['Pollutant Levels'].map(eval) tun. Anschließend kann mit der folgenden Lösung das dict in verschiedene Spalten konvertiert werden.


ein kleines Beispiel verwenden, können Sie .apply(pd.Series) verwenden:

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 

es mit dem Rest des Datenrahmen zu kombinieren, um Sie die anderen Spalten mit dem obigen Ergebnis concat können:

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 

Mit Ihrem Code funktioniert das auch, wenn ich dieweglassenTeil:

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

Ich habe 'pd.DataFrame (df [col] .tolist())' für eine lange Zeit verwendet, dachte nie über 'apply (pd.Series)'. Sehr schön. – ayhan

+0

Ich verstehe jetzt das Problem. Die Anwendung .apply (pd.Series) funktioniert nicht in meinem Dataset, da die gesamte Zeile eine Unicode-Zeichenfolge ist. Es ist: u '{' a ':' 1 ',' b ':' 2 ',' c ':' 3 '} und nicht {u'a': '1', u'b ':' 2 ', u'c ':' 3 '} wie Ihre Lösungen zeigen. Der Code kann also nicht in 3 erkennbare Spalten aufgeteilt werden. – llaffin

+0

@ayhan Eigentlich getestet, und die 'DataFrame (df ['col']. Tolist())' Ansatz ist ziemlich viel schneller als die Anwendung Ansatz! – joris

4

Try this: Die zurückgegebenen Daten von SQL hat sich zu einem Dict umgewandelt. oder könnte es "Pollutant Levels" sein ist jetzt 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 einer Zeile:

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