如何将嵌套字典的列表转换为pandas DataFrame?

5

我有一些包含嵌套字典的数据,如下所示:

mylist = [{"a": 1, "b": {"c": 2, "d":3}}, {"a": 3, "b": {"c": 4, "d":3}}]

如果我们将其转换为pandas DataFrame,
import pandas as pd 

result_dataframe = pd.DataFrame(mylist)
print(result_dataframe)

它将输出:
    a   b
  0 1   {'c': 2, 'd': 3}
  1 3   {'c': 4, 'd': 3}

我希望将字典列表转换,并忽略嵌套字典的键。我的代码如下:
new_dataframe = result_dataframe.drop(columns=["b"])
b_dict_list = [document["b"] for document in mylist]
b_df = pd.DataFrame(b_dict_list)
frames = [new_dataframe, b_df]
total_frame = pd.concat(frames, axis=1)

我的需求是 total_frame:

    a   c   d
0   1   2   3
1   3   4   3

但是我认为我的代码有些复杂。有没有简单的方法来解决这个问题?谢谢。


df_data = [{"a": el["a"], **el["b"]} for el in mylist] - Tom Wojcik
@TomWojcik 你好,如果字典有很多键会怎么样? - lazy_frog
4个回答

13

我遇到过类似的问题。我使用了 pd.json_normalize(x) ,它有效地解决了我的问题。唯一的不同之处在于数据框的列名可能略有不同。

mylist = [{"a": 1, "b": {"c": 2, "d":3}}, {"a": 3, "b": {"c": 4, "d":3}}]
df = pd.json_normalize(mylist)
print(df)

输出:

a b.c b.d
0 1 2 3
1 3 4 3

它对我有效。这是一个优雅的解决方案。谢谢! - Vladimir Obrizan

9

使用带有pop字典推导式来提取值b合并字典

a = [{**x, **x.pop('b')} for x in mylist]
print (a)
[{'a': 1, 'c': 2, 'd': 3}, {'a': 3, 'c': 4, 'd': 3}]

result_dataframe = pd.DataFrame(a)
print(result_dataframe)
   a  c  d
0  1  2  3
1  3  4  3

另一个解决方案,感谢 @Sandeep Kadapa 的贡献:

a = [{'a': x['a'], **x['b']} for x in mylist] 
#alternative
a = [{'a': x['a'], **x.get('b')} for x in mylist] 

1
这是一个非常优雅的解决方案,但不幸的是,我无法将其扩展为接受任意列的列表,因为在字典推导式中不允许解包(例如[{**x.pop(k) for k in x.keys()} for x in mylist])。有没有一种简单的方法可以使用任意列? - economy
@economy 现在我只能用手机,因为是假期,所以最好提供新的问题,同时附上样本数据和期望输出,谢谢。 - jezrael
不是一种安全的方式。x.pop会破坏原始字典。 - wsdzbm

2

或者通过将pd.Series()应用于您的方法:

最初的回答
mylist = [{"a": 1, "b": {"c": 2, "d":3}}, {"a": 3, "b": {"c": 4, "d":3}}]
result_dataframe = pd.DataFrame(mylist)
result_dataframe.drop('b',1).join(result_dataframe.b.apply(pd.Series))

   a  c  d
0  1  2  3
1  3  4  3

@jezrael 好的,已经注意到了。 :) - anky

2
我更喜欢编写一个函数,接受你的mylist并将其转换为1个嵌套层级的字典。这样做的额外好处是不需要手动知道要转换的键,例如b。因此,该函数适用于所有嵌套的一级键。"最初的回答"
mylist = [{"a": 1, "b": {"c": 2, "d":3}}, {"a": 3, "b": {"c": 4, "d":3}}]
import pandas as pd

def dropnested(alist):
    outputdict = {}
    for dic in alist:
        for key, value in dic.items():
            if isinstance(value, dict):
                for k2, v2, in value.items():
                    outputdict[k2] = outputdict.get(k2, []) + [v2]
            else:
                outputdict[key] = outputdict.get(key, []) + [value]
    return outputdict    

df = pd.DataFrame.from_dict(dropnested(mylist))
print (df)
#   a  c  d
#0  1  2  3
#1  3  4  3

If you try:

mylist = [{"a": 1, "b": {"c": 2, "d":3}, "g": {"e": 2, "f":3}}, 
          {"a": 3, "z": {"c": 4, "d":3}, "e": {"e": 2, "f":3}}]
df = pd.DataFrame.from_dict(dropnested(mylist))
print (df)
#   a  c  d  e  f
#0  1  2  3  2  3
#1  3  4  3  2  3

我们可以看到这里它可以轻松地转换键bgze,而不必定义每个嵌套键名来进行转换。这与需要定义每个嵌套键名进行转换的情况形成了对比。"Original Answer"翻译成"最初的答案"。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接