Как создать иерархический JSON n-уровня из фрейма данных pandas?
есть ли эффективный способ создания иерархического JSON (N-levels deep), где родительские значения являются ключами, а не меткой переменной? я.е:
{"2017-12-31":
{"Junior":
{"Electronics":
{"A":
{"sales": 0.440755
}
},
{"B":
{"sales": -3.230951
}
}
}, ...etc...
}, ...etc...
}, ...etc...
1. Мой тестовый фрейм данных:
colIndex=pd.MultiIndex.from_product([['New York','Paris'],
['Electronics','Household'],
['A','B','C'],
['Junior','Senior']],
names=['City','Department','Team','Job Role'])
rowIndex=pd.date_range('25-12-2017',periods=12,freq='D')
df1=pd.DataFrame(np.random.randn(12, 24), index=rowIndex, columns=colIndex)
df1.index.name='Date'
df2=df1.resample('M').sum()
df3=df2.stack(level=0).groupby('Date').sum()
2. Преобразование, которое я делаю, кажется наиболее логичной структурой для построения JSON от:
df4=df3.stack(level=[0,1,2]).reset_index()
.set_index(['Date','Job Role','Department','Team'])
.sort_index()
3. Мои попытки-пока что
я наткнулся на это хороший вопрос что решает проблему для одного уровня вложенности, используя код следующего содержания:
j =(df.groupby(['ID','Location','Country','Latitude','Longitude'],as_index=False)
.apply(lambda x: x[['timestamp','tide']].to_dict('r'))
.reset_index()
.rename(columns={0:'Tide-Data'})
.to_json(orient='records'))
...но я не могу найти способ получить вложенные .groupby()
работает:
j=(df.groupby('date', as_index=True).apply(
lambda x: x.groupby('Job Role', as_index=True).apply(
lambda x: x.groupby('Department', as_index=True).apply(
lambda x: x.groupby('Team', as_index=True).to_dict())))
.reset_index().rename(columns={0:'sales'}).to_json(orient='records'))
2 ответов
вы можете использовать itertuples для создания вложенного dict
, а затем сбросить в json
. Для этого необходимо изменить отметку времени даты на string
df4=df3.stack(level=[0,1,2]).reset_index()
df4['Date'] = df4['Date'].dt.strftime('%Y-%m-%d')
df4 = df4.set_index(['Date','Job Role','Department','Team']) \
.sort_index()
создайте вложенный dict
def nested_dict():
return collections.defaultdict(nested_dict)
result = nested_dict()
использовать itertuples
заполнить
for row in df4.itertuples():
result[row.Index[0]][row.Index[1]][row.Index[2]][row.Index[3]]['sales'] = row._1
# print(row)
а затем используйте json
модуль, чтобы свалить его.
import json
json.dumps(result)
'{"2017-12-31": {"Junior": {"Electronics": {"A": {"sales": -0.3947134370101142}, "B": {"sales": -0.9873530754403204}, " C": {"продажи": -1.1182598058984508}}, "бытовых": {"а": {"продажи": -1.1211850078098677}, "Б": {"продажи": 2.0330914483907847}, "с": {"продажи": 3.94762379718749}}}, "старший": {"электроника": {"а": {"продажи": 1.4528493451404196}, "Б": {"продажи": -2.3277322345261005}, "с": {"продажи": -2.8040263791743922}}, "Бытовая": {"а": {"продажи": 3.0972591929279663}, "Б": {"продажи": 9.884565742502392}, "с": {"продажи": 2.9359830722457576}}}}, "2018-01-31": {"Юниор": {"электроника": {"а": {"продажи": -1.3580300149125217}, "Б": {"продажи": 1.414665000013205}, "с": {"продажи": -1.432795129108244}}, "бытовых": {"а": {"продажи": 2.7783259569115346}, "Б": {"продажи": 2.717700275321333}, "с": {"продажи": 1.4358377416259644}}}, "старший": {"электроника": {"а": {"продажи": 2.8981726774941485}, "Б": {"продажи": 12.022897003654117}, "с": {"продажи": 0.01776855733076088}}, "бытовых": {"а": {"продажи": -3.342163776613092}, "Б": {"продажи": -5.283208386572307}, "с": {"продажи": 2.942580121975619}}}}}'
я столкнулся с этим и был смущен сложностью настройки OP. Вот минимальный пример и решение (на основе ответа, предоставленного @Maarten Fabré).
import collections
import pandas as pd
# build init DF
x = ['a', 'a']
y = ['b', 'c']
z = [['d'], ['e', 'f']]
df = pd.DataFrame(list(zip(x, y, z)), columns=['x', 'y', 'z'])
# x y z
# 0 a b [d]
# 1 a c [e, f]
настройте обычный, плоский, индекс, а затем сделайте это multi index
# set flat index
df = df.set_index(['x', 'y'])
# set up multi index
df = df.reindex(pd.MultiIndex.from_tuples(zip(x, y)))
# z
# a b [d]
# c [e, f]
затем введите вложенный словарь и заполните его пункт за пунктом
nested_dict = collections.defaultdict(dict)
for keys, value in df.z.iteritems():
nested_dict[keys[0]][keys[1]] = value
# defaultdict(dict, {'a': {'b': ['d'], 'c': ['e', 'f']}})
на этом этапе вы можете JSON сбросить его и т. д.