多索引数据到嵌套的对象列表



我有一些数据看起来像这样…

import pandas as pd
df = pd.DataFrame(
[[1, 2, 3, 4, 5, 6], [5, 6, 7, 8, 9, 10]],
columns=[
['a', 'a', 'b', 'b', 'c', 'c'], 
['col1', 'col2', 'col1', 'col2', 'col3', 'col4']
]
)
#      a         b         c     
#   col1 col2 col1 col2 col3 col4
# 0    1    2    3    4    5    6
# 1    5    6    7    8    9   10

我想把这个格式设置为…

formatted_data
# [{'a': {'col1': 1, 'col2': 2},
#   'b': {'col1': 3, 'col2': 4},
#   'c': {'col3': 5, 'col4': 6}},
#  {'a': {'col1': 5, 'col2': 6},
#   'b': {'col1': 7, 'col2': 8},
#   'c': {'col3': 9, 'col4': 10}}]

我确实实现了我想要的,但解决方案要么是不可读的,效率低,或。所以我想知道是否有其他更容易读懂的方法。最好保持在pandasapi内。效率在这里并不重要,因为数据量很小,而且操作必须执行一次。

def get_multi_index_key(data, col_name):
return data[col_name].to_dict("records")
def preformat_data(df, columns):
multi_index_values = zip(*[get_multi_index_key(df, key) for key in columns])
for row in multi_index_values:
yield dict(
zip(columns, row)
)
formatted_data = preformat_data(df, ["a", "b", "c"])
next(formatted_data)
# {'a': {'col1': 1, 'col2': 2}, 'b': {'col1': 3, 'col2': 4}, 'c': {'col3': 5.0, 'col4': 6.0}}

所提出的解决方案的问题是,level=1的列都在MultiIndexes之间共享,这意味着结果是…

[{'a': {'col1': 1.0, 'col2': 2.0, 'col3': nan, 'col4': nan},
'b': {'col1': 3.0, 'col2': 4.0, 'col3': nan, 'col4': nan},
'c': {'col1': nan, 'col2': nan, 'col3': 5.0, 'col4': 6.0}},
{'a': {'col1': 5.0, 'col2': 6.0, 'col3': nan, 'col4': nan},
'b': {'col1': 7.0, 'col2': 8.0, 'col3': nan, 'col4': nan},
'c': {'col1': nan, 'col2': nan, 'col3': 9.0, 'col4': 10.0}}]

您可以尝试使用to_dict

out = [df.loc[[x]].stack().reset_index(level=0,drop=True).to_dict() for x in df.index]
Out[608]: 
[{'a': {'col1': 1, 'col2': 2}, 'b': {'col1': 3, 'col2': 4}},
{'a': {'col1': 5, 'col2': 6}, 'b': {'col1': 7, 'col2': 8}}]

Pandas解决方案

s = df.stack(0)
s['r'] = s.to_dict('r')
s['r'].unstack().to_dict('r')

对应OP更新的一般pandas解决方案:

s = df.melt(var_name=['l0', 'l1'], ignore_index=False)
s.groupby([s.index, 'l0']).apply(lambda s: dict(zip(s.l1, s.value))).unstack().to_dict('records')

[{'a': {'col1': 1, 'col2': 2},
'b': {'col1': 3, 'col2': 4},
'c': {'col3': 5, 'col4': 6}},
{'a': {'col1': 5, 'col2': 6},
'b': {'col1': 7, 'col2': 8},
'c': {'col3': 9, 'col4': 10}}]

可以了

def nest(d: dict) -> dict:
result = {}
for key, value in d.items():
target = result
for k in key[:-1]:  # traverse all keys but the last
target = target.setdefault(k, {})
target[key[-1]] = value
return result
def df_to_nested_dict(df: pd.DataFrame) -> dict:
d = df.to_dict(orient='index')
return {k: nest(v) for k, v in d.items()}
result = df_to_nested_dict(df)

如果您打印result,您将得到所需的输出-

{
0: {
'a': {'col1': 1, 'col2': 2}, 
'b': {'col1': 3, 'col2': 4}
},
1: {
'a': {'col1': 5, 'col2': 6}, 
'b': {'col1': 7, 'col2': 8}
}
}

最新更新