嵌套字典 --> 改革字典 -->多索引数据帧 -->堆叠。结果不符合预期,因为值被分离



我有一个嵌套的字典,看起来像这样:

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条目所需的一些代码行。

最新更新