我把数据保存在一个文件夹中 postgreSQL
数据库我正在使用python2.7查询这些数据,并将其转换为一个 Dataframe 。但是,此 Dataframe 的最后一列中有一个值字典。 Dataframe 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"}
我需要将此列拆分为单独的列,以便dataframe`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”。它们总是以相同的顺序出现(“a'第一,'b'第二,'c'第三”)。
下面的代码用于工作并返回我想要的内容(df2)。
objs = [df, pandas.DataFrame(df['Pollutant Levels'].tolist()).iloc[:, :3]]
df2 = pandas.concat(objs, axis=1).drop('Pollutant Levels', axis=1)
print(df2)
我上周刚刚运行了这段代码,它运行得很好。但是现在我的代码被破坏了,我从第[4]行得到了这个错误:
IndexError: out-of-bounds on slice (end)
我没有对代码做任何更改,但现在得到了错误。我觉得这是因为我的方法不健全或不恰当。
如果您对如何将此列表列拆分为单独的列有任何建议或指导,我们将不胜感激!
编辑:我认为 .tolist()
和.apply方法不适用于我的代码,因为它是一个unicode字符串,即:
# My data format
u{'a': '1', 'b': '2', 'c': '3'}
# and not
{u'a': '1', u'b': '2', u'c': '3'}
数据是从数据库导入的 postgreSQL
此格式的数据库。在这个问题上有什么帮助或想法吗?有没有转换unicode的方法?
13条答案
按热度按时间bksxznpy1#
梅林的答案更好,也非常简单,但我们不需要lambda函数。字典的评估可以通过以下两种方式之一安全地忽略,如下所示:
方法1:两步
方式2:以上两个步骤可以一次完成:
ykejflvf2#
你可以用
join
具有pop
+tolist
. 性能可与concat
具有drop
+tolist
,但有些人可能会发现这种语法更简洁:采用其他方法进行基准测试:
vsdwdz233#
1000万行的大型数据集的速度比较
pieyvz9o4#
如何使用pandas将一列词典拆分为单独的列?
dataframe(df['val'].tolist())是用于分解字典列的规范方法
这是你用彩色图表做的证明。
基准测试代码供参考。
请注意,我只是为爆炸计时,因为这是回答这个问题最有趣的部分——结果构造的其他方面(例如是否使用
pop
或drop
)与讨论无关,可以忽略(但应注意,使用pop
避免后续行动drop
调用,因此最终的解决方案的性能会更好一些,但我们仍在列出该列并将其传递给pd.DataFrame
无论如何)。另外,,
pop
破坏性地改变输入 Dataframe ,使其更难在基准测试代码中运行,而基准测试代码假定输入在测试运行期间没有改变。对其他解决方案的批评
df['val'].apply(pd.Series)
对于大n来说非常慢,因为pandas为每一行构造系列对象,然后继续从它们构造 Dataframe 。对于较大的n,性能下降到分钟或小时的数量级。pd.json_normalize(df['val']))
速度变慢仅仅是因为json_normalize
用于处理更复杂的输入数据,特别是具有多条记录路径和元数据的深度嵌套json。我们有一个简单的平板电脑pd.DataFrame
足够了,所以如果你的口述是扁平的,就用它。一些答案表明
df.pop('val').values.tolist()
或df.pop('val').to_numpy().tolist()
. 我不认为它有多大的区别,无论你是否列出该系列或numpy阵列。直接列出该系列只需一个操作,而且速度并不慢,因此我建议避免在中间步骤生成numpy数组。dpiehjr45#
单线解决方案如下:
6tdlim6h6#
wfsdck307#
my_df = pd.DataFrame.from_dict(my_dict, orient='index', columns=['my_col'])
.. 将正确解析dict(将每个dict键放入单独的df列中,将键值放入df行中),这样dict就不会首先被压缩到单个列中。arknldoa8#
我已将这些步骤连接到一个方法中,您只需传递dataframe和包含要展开的dict的列:
eoxn13cs9#
要将字符串转换为实际的dict,可以执行以下操作
df['Pollutant Levels'].map(eval)
. 然后,可以使用下面的解决方案将dict转换为不同的列。使用一个小示例,您可以使用
.apply(pd.Series)
:要将其与 Dataframe 的其余部分结合起来,您可以
concat
具有上述结果的其他列:使用您的代码,如果我省略
iloc
第部分:czq61nw110#
我知道这个问题很老了,但我来这里是为了寻找答案。实际上,现在有一种更好(更快)的方法使用
json_normalize
:这避免了昂贵的应用函数。。。
xmjla07d11#
规范化一列平面、一个标高的最快方法
dicts
,根据shijith在本回答中进行的时间分析:df.join(pd.DataFrame(df.pop('Pollutants').values.tolist()))
它不会解决列的其他问题list
或dicts
下面列出的,例如带有NaN
,或嵌套dicts
.pd.json_normalize(df.Pollutants)
明显快于df.Pollutants.apply(pd.Series)
见%%timeit
在下面对于100万行,.json_normalize
它的速度是它的47倍.apply
.无论是从文件中读取数据,还是从数据库或api返回的对象中读取数据,都可能不清楚
dict
专栏有dict
或str
类型。如果列中的词典是
str
类型,则必须将其转换回dict
类型,使用ast.literal_eval
.使用
pd.json_normalize
转换dicts
具有keys
作为标题和values
行。还有其他参数(例如。
record_path
&meta
)用于处理嵌套dicts
.使用
pandas.DataFrame.join
要组合原始 Dataframe ,df
,使用pd.json_normalize
如果索引不是整数(如示例中所示),请首先使用df.reset_index()
在执行规格化和联接之前,获取整数索引。最后,使用
pandas.DataFrame.drop
,以删除不需要的列dicts
请注意,如果该列有NaN
,必须用空的dict
df.Pollutants = df.Pollutants.fillna({i: {} for i in df.index})
如果'Pollutants'
列是字符串,请使用'{}'
.另请参见如何使用nans?规范化列?。
%%时间
ohfgkhjo12#
试试这个:从sql返回的数据必须转换成dict,或者是
"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 )
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
eivnm1vs13#
我强烈推荐提取“污染物”列的方法:
df_pollutants = pd.DataFrame(df['Pollutants'].values.tolist(), index=df.index)
比以前快多了df_pollutants = df['Pollutants'].apply(pd.Series)
当df的大小是巨大的。