2016-07-06 72 views
21

我將數據保存在postgreSQL數據庫中。我使用Python2.7查詢這些數據並將其轉換爲Pandas DataFrame。但是,此數據框的最後一列中包含一個字典(或列表?)的值。數據框看起來是這樣的:將Pandas Column中的字典/列表拆分爲獨立列

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

我需要此列拆分爲單獨的列,使數據幀是這樣的:

[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 

我遇到的主要問題是,名單都沒有相同的長度。但是,所有列表只包含相同的3個值:a,b和c。它們總是以相同的順序出現(第一,第二,第三)。

下面的代碼用於工作並返回我想要的(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) 

我剛剛在上週運行此代碼,它工作正常。但現在我的代碼被打破,我從線[4]這樣的錯誤:

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

我做任何更改代碼,但我現在得到的錯誤。我覺得這是由於我的方法不健全或不適當。

任何有關如何將這一列列表拆分爲單獨列的建議或指導將受到超級讚賞!

編輯:我認爲.tolist()和。適用方法不工作對我的代碼,因爲它是一個unicode字符串,即:

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

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

的數據從PostgreSQL數據庫以這種格式導入。對此問題有何幫助或想法?有沒有辦法轉換unicode?

+0

我有一個稍微不同的解決辦法回答,但是,你的代碼實際上應該也工作得很好。使用我下面的虛擬示例,如果我省略'iloc'部分 – joris

+0

,則使用pandas 0.18.1。'iloc [:,:3]'假定會有3個項目,可能還有更新的數據切片只有1或2(例如,在'索引8813'中恰好沒有'b')? – dwanderson

回答

35

要將字符串轉換爲實際字典,可以執行df['Pollutant Levels'].map(eval)。之後,下面的解決方案可用於將字典轉換爲不同的列。


用一個小例子,你可以使用.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 

要使用數據框的其餘部分結合起來,你可以用上面的結果concat其他列:

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 

使用你的代碼,這也適用,如果我忽略iloc部分:

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

我一直在使用'pd.DataFrame(df [col] .tolist())',從來沒有想過應用(pd.Series)'。非常好。 – ayhan

+0

我現在意識到了這個問題。 .apply(pd.Series)不能用於我的數據集,因爲整行是一個unicode字符串。它是:u'{'a':'1','b':'2','c':'3'}而不是{u'a':'1',u'b':'2', u'c':'3'},正如你的解決方案所示。所以代碼不能將它分成3個可識別的列。 – llaffin

+0

@ayhan其實,測試它,'DataFrame(df ['col']。tolist())'方法比apply方法快一些! – joris

4

試試這個:從SQL返回數據必須轉換成詞典。 或可能是"Pollutant Levels"現在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

是在一行:

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