2016-07-06 573 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)`