看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
在数据清洗工作中,会遇到 json 格式数据,json 中包含大量的字典类型(dict)数据,我们往往要将这些字典数据转为结构化地的数据格式。在本文中我们需要将字典中的值相加。
源数据及生成代码如下:
import pandas as pd
df = pd.DataFrame({
'a':[0, {'x':3, 'y':1},0],
'b':[1, {'x':4, 'y':5}, {'x':1, 'y':2}]
})
df
'''
a b
0 0 1
1 {'x': 3, 'y': 1} {'x': 4, 'y': 5}
2 0 {'x': 1, 'y': 2}
'''
第二行(索引为1)和最后一行(索引为2)都包含了字典形式的字符串,现在需求是需要将每个字典形式的数据中的值部分相加,如(1,'a')中的值最终为 4.最后再在表的右侧增加一个汇总加和列,结果如下:
'''
a b sum
0 0 1 1
1 4 9 13
2 0 3 3
'''
由于受字典形式的字符串影响,所有列都为 object 类型。首先要解决的是识别字符形式的字典数据,将其转为数值,可以写一个函数来处理。函数的逻辑为:如果字符串中有{
符号(也可以按其他特征判断),就按字典字符串处理,如果没有就不做处理。在处理字典字符串时,可以用 Python 的 eval 来转为字典代码,最后用pd.Series(d).sum()
将字典转为 Series 再用 sum 加和。
最后,根据需求,用 assign 再增加一列,此列为当前行的和。
根据以上思路,定义的数据值处理逻辑函数如下:
def get_dict_sum(val):
val = str(val)
if '{' in val:
d = eval(val)
return pd.Series(d).sum()
else:
return val
函数中,先将值转为 str,再判断 str 中否包含 {
,如果不包含说明不是字典形式,不需要处理直接返回原值。如果包含,则将字符传入 eval
处理,产生一个字典,再将这个字典用 pd.Series(d)
转为序列,最后求和得到结果。
接下来,应用以上函数,由于要对 DataFrame 的每个值进行处理,因此需要用 applymap
来应用函数。
df.applymap(get_dict_sum)
'''
a b
0 0 1
1 4 9
2 0 3
'''
这样,就对数据进行了清洗。最后一步,用≈增加一个求和列:
(
df.applymap(get_dict_sum)
.astype(int)
.assign(sum=lambda x: x.agg(sum, axis=1))
)
'''
a b sum
0 0 1 1
1 4 9 13
2 0 3 3
'''
在 applymap
中,将新列命名为 sum,用 agg 调用 sum 函数,因为是行方向的求和,在 agg 中还要传入 axis 的值为 1,就得到了最终结果。
注:最新版本 pandas 需要将上边的 applymap 替换为 map。
也可以用以下方案进行处理(适用于 pandas 2.1+):
(
df.astype(str)
.map(eval)
.map(lambda x: sum(x.values()) if isinstance(x, dict) else x)
.assign(sum=lambda x: x.sum(axis=1))
)
基本思路是,将所有数据转为字符串,为我们应用 eval 作准备,因为部分数据是整型,不能传入 eval。
接下来,全部应用 eval,转为 Python 对象,数字就转为数字,字典字符串就转为字典。
再下来,通过判断数字类型来进行计算:字典将所有的值相加,否则原样不变,这样就完成了基础表的处理。
最后,再增加一个按行的加和列。
这样就完成了需求。
(完)
更新时间:Aug. 18, 2024, 3:41 p.m. 标签:pandas python 字典 函数