我有一个嵌套的字典,看起来像这样:
test_dict = {'header1_1': {'header2_1': {'header3_1': {'header4_1': ['322.5', 330.0, -0.28],
'header4_2': ['322.5', 332.5, -0.26]},
'header3_2': {'header4_1': ['285.0', 277.5, -0.09],
'header4_2': ['287.5', 277.5, -0.12]}},
'header2_2': {'header3_1': {'header4_1': ['345.0', 357.5, -0.14],
'header4_2': ['345.0', 362.5, -0.14]},
'header3_2': {'header4_1': ['257.5', 245.0, -0.1],
'header4_2': ['257.5', 240.0, -0.08]}}}}
有4层报头,每层可以有多个值,例如,header1_1, header1_2。一旦你指定了这些头的组合,你就有了一个包含3个值的列表。
我想把它放到一个数据框架中,所以我创建了一个经过改造的字典:
reformed_dict = {}
for outerKey, innerDict in test_dict.items():
for innerKey, innerDict2 in innerDict.items():
for innerKey2, innerDict3 in innerDict2.items():
for innerKey3, values in innerDict3.items():
reformed_dict[(outerKey,
innerKey, innerKey2, innerKey3)] = values
reformed_dict
和改革字典的样子:
{(‘header1_1’,‘header2_1’,‘header3_1’,‘header4_1’):("322.5",330.0,-0.28),
(‘header1_1’,‘header2_1’,‘header3_1’,‘header4_2’):("322.5",332.5,-0.26),
(‘header1_1’,‘header2_1’,‘header3_2’,‘header4_1’):("285.0",277.5,-0.09),
(‘header1_1’,‘header2_1’,‘header3_2’,‘header4_2’):("287.5",277.5,-0.12),
(‘header1_1’,‘header2_2’,‘header3_1’,‘header4_1’):("345.0",357.5,-0.14),
(‘header1_1’,‘header2_2’,‘header3_1’,‘header4_2’):("345.0",362.5,-0.14),
(‘header1_1’,‘header2_2’,‘header3_2’,‘header4_1’):("257.5",245.0,-0.1),
(‘header1_1’,‘header2_2’,‘header3_2’,‘header4_2’):["257.5",240.0,-0.08]}
将其放入数据框架:
df = pandas.DataFrame(reformed_dict)
header1_1
header2_1 header2_2
header3_1 header3_1 header3_2
header4_1 header4_2 header4_1 header4_2 header4_1 header4_2 header4_1 header4_2 header4_1 header4_2 header4_1 header4_2 header4_1 header4_2 header4_2 header4_1 header4_2 header4_2 header4_1 header4_2
0 322.5 322.5 285.0 287.5 345.0 345.0 257.5
1 330.0 332.5 277.5 277.5 357.5 362.5 245.0 240.0
2 -0.28 -0.26 -0.09 -0.12 -0.14 -0.14 -0.1 -0.08
我想做的是让所有的列标头都是行标头,并且每个标头组合有3列,我将列命名为Val1, Val2, Val3。
所以我使用df.stack()将列标头推入行:
df_1 = df.stack(level=0)
df_2 = df_1.stack(level=0)
df_3 = df_2.stack(level=0)
df_4 = df_3.stack(level=0)
print(df_4)
结果是:
header1_1 header2_1 header3_1 header4_1 322.5
header4_2 322.5
header3_1 header4_1 285.0
header2_2 header3_1 345.0
header4_1 257.5
header3_1 header4_1 330.0
header3_1 header4_1 277.5
header4_2 277.5
header2_2 header3_1 header4_1 357.5
header4_2362.5
header3_2 header4_1 245.0
header4_1 240.0
2 header1_1 header2_1 header4_1 -0.28
header4_2 -0.26
header3_1 header4_1 -0.09
header4_2 -0.12
header2_2 header3_1 header4_1 -0.14
header3_2 header4_1 -0.1
header4_2 -0.08
这不是我想要的布局,因为我希望每个列表中的3个值都在同一行,类似于它们在改革后的字典中的方式。
我怎样才能做到这一点?
您要查找的是MultiIndex。
将字典的键转换为索引并使用字典值作为数据:
keys = reformed_dict.keys()
index = pd.MultiIndex.from_tuples(keys, names=["header1", "header2", "header3", "header4"])
values = [reformed_dict[k] for k in keys]
df = pd.DataFrame(data=values, index=index)
输出:
header1 header2 header3 header4
header1_1 header2_1 header3_1 header4_1 322.5 330.0 -0.28
header4_2 322.5 332.5 -0.26
header3_2 header4_1 285.0 277.5 -0.09
header4_2 287.5 277.5 -0.12
header2_2 header3_1 header4_1 345.0 357.5 -0.14
header4_2 345.0 362.5 -0.14
header3_2 header4_1 257.5 245.0 -0.10
header4_2 257.5 240.0 -0.08
如果您希望索引为列:
df = df.reset_index()
输出:
header1 header2 header3 header4 0 1 2
0 header1_1 header2_1 header3_1 header4_1 322.5 330.0 -0.28
1 header1_1 header2_1 header3_1 header4_2 322.5 332.5 -0.26
2 header1_1 header2_1 header3_2 header4_1 285.0 277.5 -0.09
3 header1_1 header2_1 header3_2 header4_2 287.5 277.5 -0.12
4 header1_1 header2_2 header3_1 header4_1 345.0 357.5 -0.14
5 header1_1 header2_2 header3_1 header4_2 345.0 362.5 -0.14
6 header1_1 header2_2 header3_2 header4_1 257.5 245.0 -0.10
7 header1_1 header2_2 header3_2 header4_2 257.5 240.0 -0.08
尝试:
test_dict =
{'header1_1': {'header2_1': {'header3_1': {'header4_1': ['322.5', 330.0, -0.28],
'header4_2': ['322.5', 332.5, -0.26]},
'header3_2': {'header4_1': ['285.0', 277.5, -0.09],
'header4_2': ['287.5', 277.5, -0.12]}},
'header2_2': {'header3_1': {'header4_1': ['345.0', 357.5, -0.14],
'header4_2': ['345.0', 362.5, -0.14]},
'header3_2': {'header4_1': ['257.5', 245.0, -0.10],
'header4_2': ['257.5', 240.0, -0.08]}}}}
#from pprint import pprint
#pprint(test_dict)
from collections import defaultdict
import pandas as pd
dct_N = defaultdict(list)
total_rows = 0
def fillDataFrameDict(dct, level=0):
global dct_N, total_rows
for key, value in dct.items():
if not isinstance(value, dict):
dct_N[f'headerNo_{level+1}'].append(key)
total_rows += 1
dct_N['body'].append(value)
for key_N, value_N in dct_N.items():
dct_N[key_N] = value_N + (total_rows-len(value_N))*[value_N[-1]]
else:
dct_N[f'headerNo_{level+1}'].append(key)
fillDataFrameDict(value, level+1)
fillDataFrameDict(test_dict)
df = pd.DataFrame(dct_N)
print(df)
给了:
headerNo_1 headerNo_2 headerNo_3 headerNo_4 body
0 header1_1 header2_1 header3_1 header4_1 [322.5, 330.0, -0.28]
1 header1_1 header2_1 header3_1 header4_2 [322.5, 332.5, -0.26]
2 header1_1 header2_1 header3_2 header4_1 [285.0, 277.5, -0.09]
3 header1_1 header2_1 header3_2 header4_2 [287.5, 277.5, -0.12]
4 header1_1 header2_2 header3_1 header4_1 [345.0, 357.5, -0.14]
5 header1_1 header2_2 header3_1 header4_2 [345.0, 362.5, -0.14]
6 header1_1 header2_2 header3_2 header4_1 [257.5, 245.0, -0.1]
7 header1_1 header2_2 header3_2 header4_2 [257.5, 240.0, -0.08]
当处理深度嵌套列表或字典时,使用递归遍历嵌套分支是递归使用有意义的完美情况。
在指向body
元素的路径下,上面的递归函数测试字典值的类型,并在值不是字典时停止递归调用。
在递归调用期间跟踪行级别和行数允许用适当的值填充列,因此在每个列中有相同数量的行元素用于创建pandas DataFrame。
collections
模块提供的defaultdict(list)
字典对象(它是标准Python安装的一部分)创建一个空列表作为值,并返回尚未存储在字典中的键。这节省了在用项填充列表之前在字典中创建第一个key:value
条目所需的一些代码行。