Python 将数据帧转换为嵌套dict
我正在寻找一种将数据帧转换为嵌套字典的通用方法 这是一个示例数据帧Python 将数据帧转换为嵌套dict,python,pandas,Python,Pandas,我正在寻找一种将数据帧转换为嵌套字典的通用方法 这是一个示例数据帧 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 }
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
函数,但还没有成功地使其适用于超过一个级别(两列)。请参见它们的一些选项,您可以通过这些选项以几种不同的形式获取输出
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格式的方法,然后逐字地评估它以创建实际的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]]
我不明白为什么您的dict中没有一个
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}}}
不过,使用非熊猫方法可能更简单:
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
你可以像下面那样简单地重建你的字典
>>> 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])
与
要获得所需的输出:
>>> 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)
下面是使用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
或:
data.groupby(by='name',sort=False).apply(lambda x:x.to_dict(orient='records'))
应该会有帮助,这是最简单的方法。hey@Jeff,我尝试了所有的选项+大约10篇关于类似主题的帖子,但仍然没有获得所需的输出。你也可以尝试
df.to_json()
,同样有各种选项,这是一个很好的提示,to_json(orient=“values”)
提供了路径,现在我需要考虑如何从中构建dict。请参见上面的方法!你为什么用ast?to_json给出了相同的输出。这里有一个问题基本上是向后的:现在将g.ix
替换为g.iloc
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]})