考虑以下DataFrame:
import pandas as pd
df = pd.DataFrame({'id': [1, 2, 3],
'json_col': [ [{'aa' : 1, 'ab' : 1}, {'aa' : 3, 'ab' : 2, 'ac': 6}],
[{'aa' : 1, 'ab' : 2, 'ac': 1}, {'aa' : 5}],
[{'aa': 3, 'ac': 2}] ]})
df
Out[134]:
id json_col
0 1 [{'aa': 1, 'ab': 1}, {'aa': 3, 'ab': 2, 'ac': 6}]
1 2 [{'aa': 1, 'ab': 2, 'ac': 1}, {'aa': 5}]
2 3 [{'aa': 3, 'ac': 2}]
我们可以看到每个ID都有一个json列表。
我希望对于'id'
中的每个'row'
及其列表中的每个对应json,都拥有一个DataFrame
。因此,以下DataFrame
将如下所示:
id aa ab ac
0 1 1 1.0 NaN
1 1 3 2.0 6.0
2 2 1 2.0 1.0
3 2 5 NaN NaN
4 3 3 NaN 2.0
我们可以看到,id '1'
的列表中有2个对应的json,因此它在新的DataFrame
中获得了2行
使用 panda,numpy或json 功能是否有Python方式?
setup = """
import pandas as pd
df = pd.DataFrame({'id': [1, 2, 3],
'json_col': [ [{'aa' : 1, 'ab' : 1}, {'aa' : 3, 'ab' : 2, 'ac': 6}],
[{'aa' : 1, 'ab' : 2, 'ac': 1}, {'aa' : 5}],
[{'aa': 3, 'ac': 2}] ]})
"""
s1 = """
df = pd.concat(
[pd.DataFrame(j, index=[i]*len(j)) for i, j in enumerate(df['json_col'], 1)],
sort=False
)
"""
s2 = """
recs = df.apply(lambda x: [{**{'id': x.id}, **d} for d in x.json_col], axis=1).sum()
df2 = pd.DataFrame.from_records(recs)
"""
%timeit(s1, setup)
52.3 ns ± 2.6 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%timeit(s2, setup)
50.6 ns ± 3.28 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
答案 0 :(得分:1)
完成此操作的一种简短方法如下,尽管我不是亲自认为它非常具有Python风格,因为该代码有点难以阅读,并且性能不佳,但是对于小数据而言努力解决这个问题就可以了:
recs = df.apply(lambda x: [{**{'id': x.id}, **d} for d in x.json_col], axis=1).sum()
df2 = pd.DataFrame.from_records(recs)
# outputs:
aa ab ac id
0 1 1.0 NaN 1
1 3 2.0 6.0 1
2 1 2.0 1.0 2
3 5 NaN NaN 2
4 3 NaN 2.0 3
所应用的lambda通过将{id: x.id}
的内容与x.json_col
(其中x是一行)的字典列表中的每个字典合并来创建新字典。
然后将其相加。由于汇总元素列表会把它们组合成一个大元素列表,因此recs具有以下形式
[{'id': 1, 'aa': 1, 'ab': 1},
{'id': 1, 'aa': 3, 'ab': 2, 'ac': 6},
{'id': 2, 'aa': 1, 'ab': 2, 'ac': 1},
{'id': 2, 'aa': 5},
{'id': 3, 'aa': 3, 'ac': 2}]
然后从记录中简单地构造一个新的数据框。
答案 1 :(得分:1)
这是将所有json_col
的字典列表转换为DataFrame
并将它们连接在一起并进行一些调整以创建id
列的一种快速方法:
In [51]: df = pd.concat(
[pd.DataFrame(j, index=[i]*len(j)) for i, j in enumerate(json_col, 1)],
sort=False
)
In [52]: df.index.name = 'id'
In [53]: df.reset_index()
Out[53]:
id aa ab ac
0 1 1 1.0 NaN
1 1 3 2.0 6.0
2 2 1 2.0 1.0
3 2 5 NaN NaN
4 3 3 NaN 2.0