将 pandas DataFrame 转换为嵌套字典
Posted
技术标签:
【中文标题】将 pandas DataFrame 转换为嵌套字典【英文标题】:Convert pandas DataFrame to a nested dict 【发布时间】:2013-11-16 20:46:19 【问题描述】:我正在寻找一种将 DataFrame 转换为嵌套字典的通用方法
这是一个示例数据框
name v1 v2 v3
0 A A1 A11 1
1 A A2 A12 2
2 B B1 B12 3
3 C C1 C11 4
4 B B2 B21 5
5 A A2 A21 6
列数可能不同,列名也可能不同。
像这样:
'A' :
'A1' : 'A11' : 1
'A2' : 'A12' : 2 , 'A21' : 6 ,
'B' :
'B1' : 'B12' : 3 ,
'C' :
'C1' : 'C11' : 4
实现这一目标的最佳方法是什么?
我得到的最接近的是zip
函数,但还没有设法使它工作超过一个级别(两列)。
【问题讨论】:
这里有个问题基本上是倒过来的:***.com/questions/13575090/… 【参考方案1】:请参阅here,因为它们是您可以传递的一些选项,以获取多种不同形式的输出。
In [5]: df
Out[5]:
name v1 v2 v3
0 A A1 A11 1
1 A A2 A12 2
2 B B1 B12 3
3 C C1 C11 4
4 B B2 B21 5
5 A A2 A21 6
In [6]: df.to_dict()
Out[6]:
'name': 0: 'A', 1: 'A', 2: 'B', 3: 'C', 4: 'B', 5: 'A',
'v1': 0: 'A1', 1: 'A2', 2: 'B1', 3: 'C1', 4: 'B2', 5: 'A2',
'v2': 0: 'A11', 1: 'A12', 2: 'B12', 3: 'C11', 4: 'B21', 5: 'A21',
'v3': 0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6
这是一种创建 json 格式的方法,然后从字面上对其进行 eval 以创建一个实际的 dict
In [11]: import ast
In [15]: ast.literal_eval(df.to_json(orient='values'))
Out[15]:
[['A', 'A1', 'A11', 1],
['A', 'A2', 'A12', 2],
['B', 'B1', 'B12', 3],
['C', 'C1', 'C11', 4],
['B', 'B2', 'B21', 5],
['A', 'A2', 'A21', 6]]
【讨论】:
嘿@Jeff,我尝试了所有选项 + 大约 10 篇关于 SO 中类似主题的帖子,但仍未获得所需的输出。 你也可以试试df.to_json()
,又有多种选择
这是一个很好的提示,to_json(orient="values")
给了我路径,现在我需要弄清楚如何从中构建一个字典。
见上文如何做到这一点!
你为什么使用 ast ? to_json 给出相同的输出。【参考方案2】:
我不明白为什么您的字典中没有B2
。我也不确定在重复列值的情况下你想要发生什么(我的意思是除了最后一个之外的所有值。)假设第一个是疏忽,我们可以使用递归:
def recur_dictify(frame):
if len(frame.columns) == 1:
if frame.values.size == 1: return frame.values[0][0]
return frame.values.squeeze()
grouped = frame.groupby(frame.columns[0])
d = k: recur_dictify(g.ix[:,1:]) for k,g in grouped
return d
产生
>>> df
name v1 v2 v3
0 A A1 A11 1
1 A A2 A12 2
2 B B1 B12 3
3 C C1 C11 4
4 B B2 B21 5
5 A A2 A21 6
>>> pprint.pprint(recur_dictify(df))
'A': 'A1': 'A11': 1, 'A2': 'A12': 2, 'A21': 6,
'B': 'B1': 'B12': 3, 'B2': 'B21': 5,
'C': 'C1': 'C11': 4
不过,使用非 pandas 方法可能更简单:
def retro_dictify(frame):
d =
for row in frame.values:
here = d
for elem in row[:-2]:
if elem not in here:
here[elem] =
here = here[elem]
here[row[-2]] = row[-1]
return d
【讨论】:
现在用g.iloc
替换g.ix
【参考方案3】:
你可以像下面这样简单地重建你的字典
>>> result =
>>> for lst in df.values:
... leaf = result
... for path in lst[:-2]:
... leaf = leaf.setdefault(path, )
... leaf.setdefault(lst[-2], list()).append(lst[-1])
...
>>> result
'A': 'A1': 'A11': [1], 'A2': 'A21': [6], 'A12': [2], 'C': 'C1': 'C11': [4], 'B': 'B1': 'B12': [3], 'B2': 'B21': [5]
如果您确定您的叶子不会重叠,请替换最后一行
... leaf.setdefault(lst[-2], list()).append(lst[-1])
与
... leaf[lst[-2]] = lst[-1]
得到你想要的输出:
>>> result
'A': 'A1': 'A11': 1, 'A2': 'A21': 6, 'A12': 2, 'C': 'C1': 'C11': 4, 'B': 'B1': 'B12': 3, 'B2': 'B21': 5
用于测试的样本数据:
import pandas as pd
data = 'name': ['A','A','B','C','B','A'],
'v1': ['A1','A2','B1','C1','B2','A2'],
'v2': ['A11','A12','B12','C11','B21','A21'],
'v3': [1,2,3,4,5,6]
df = pd.DataFrame.from_dict(data)
【讨论】:
【参考方案4】:这是另一个使用 defaultdict 的解决方案
df = pd.DataFrame('name': 0: 'A', 1: 'A', 2: 'B', 3: 'C', 4: 'B', 5: 'A',
'v1': 0: 'A1', 1: 'A2', 2: 'B1', 3: 'C1', 4: 'B2', 5: 'A2',
'v2': 0: 'A11', 1: 'A12', 2: 'B12', 3: 'C11', 4: 'B21', 5: 'A21',
'v3': 0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6)
output = defaultdict(dict)
for lst in df.values:
try:
output[lst[0]][lst[1]].update(lst[2]:lst[3])
except KeyError:
output[lst[0]][lst[1]] =
finally:
output[lst[0]][lst[1]].update(lst[2]:lst[3])
output
或:
output = defaultdict(dict)
for row in df.values:
item1,item2 = row[0:2]
if output.get(item1, ).get(item2) == None:
output[item1][item2] =
output[item1][item2].update(row[2]:row[3])
【讨论】:
【参考方案5】:data.groupby(by='name', sort=False).apply(lambda x: x.to_dict(orient='records'))
应该有帮助,而且是最简单的方法。
【讨论】:
以上是关于将 pandas DataFrame 转换为嵌套字典的主要内容,如果未能解决你的问题,请参考以下文章
将 Pandas Dataframe 转换为表记录的嵌套 JSON