Присвоение значения вложенному словарю в цикле python
Не могу понять и исправить ситуацию с присвоением значения во вложенном словаре в цикле:
from openpyxl.utils import get_column_letter, column_index_from_string
import openpyxl, time
report_book = 'xls/DOR.xlsx' #адрес отчета
summ_coll_if = 'Сумма продаж (руб.)' #столбец по которому идет суммирование
set_stream = {'Традиция',}
set_category = {'SD Red', 'FD', 'DG Capsules', 'DG Equipment', 'MIXES',
'SD Gold', 'BISTROFF', 'Breakfast Cereals', 'Cereal bars',
'BOXES', 'TABLETS', 'COUNTLINES', 'SUGAR', 'CONFETTI',
'CULINARY', 'PURINA', 'OTHER DRINKS'}
set_people = {'TSM1', 'TSM2' }
set_tier = {'Tier TT', 'Tier 3'}
def SummValue (report: str, summ_coll: str, set_people: set, set_category: set, set_tier: set, set_stream: set, book_list: int) -> dict:
wb = openpyxl.load_workbook(report, read_only=False, data_only=True) # открываем книгу
wb.active = book_list # делаем первый лист активным
sheet = wb.active # присваиваем переменной активный лист
summ = 0
result_dict = dict.fromkeys(set_people, dict.fromkeys(set_tier, dict.fromkeys(set_stream, dict.fromkeys(set_category, 0)))) #создаем словарь
for cell in sheet['1']: # ищим в заголовках колонку для суммирования
if cell.value == summ_coll: # проверяем колонку для суммирования
column = get_column_letter(cell.column) # преобразем кол-ный кол колонки в адрес
for i in sheet[column]: # проверяем каждую строку колонки
if i.value != cell.value: # если строка != названию
list_of_values = set() # создаем пустое множество
for cell in sheet[i.row]: # проходим по всем значениям текущей строки
list_of_values.add(cell.value) # все значения текущей строки добавляем в множество
for people in set_people:
new_set = set()
new_set.add(people)
for tier in set_tier:
new_set1 = set()
new_set1.update(new_set)
new_set1.add(tier)
for stream in set_stream:
new_set2 = set()
new_set2.update(new_set1)
new_set2.add(stream)
for category in set_category:
new_set3 = set()
new_set3.update(new_set2)
new_set3.add(category)
if new_set3.intersection(list_of_values) == new_set3:
summ = result_dict[people][tier][stream][category] + i.value
summ = float('{0:.2f}'.format(summ))
result_dict[people][tier][stream][category] = summ
else:
continue
return result_dict
result = SummValue(report_book, summ_coll_if, set_people, set_category, set_tier, set_stream, 0)
print(result)
На данный момент данная функция присваивает всем people, tier, stream и category одно и тоже значение summ, хотя в документе .xlsx данные суммы разные.
Вот результат данной функции:
{'TSM2':
{'Tier 3':
{'Традиция':
{'BOXES': 5722.96, 'CONFETTI': 0, 'PURINA': 371448.13, 'CULINARY': 296151.43, 'OTHER DRINKS': 0, 'DG Capsules': 2438.46, 'Cereal bars': 113197.03, 'COUNTLINES': 538179.44, 'TABLETS': 133178.0, 'DG Equipment': 0, 'BISTROFF': 23278.92, 'SUGAR': 27448.54, 'FD': 1091256.04, 'MIXES': 267983.8, 'SD Gold': 0, 'Breakfast Cereals': 263496.46, 'SD Red': 1311766.14}},
'Tier TT':
{'Традиция':
{'BOXES': 5722.96, 'CONFETTI': 0, 'PURINA': 371448.13, 'CULINARY': 296151.43, 'OTHER DRINKS': 0, 'DG Capsules': 2438.46, 'Cereal bars': 113197.03, 'COUNTLINES': 538179.44, 'TABLETS': 133178.0, 'DG Equipment': 0, 'BISTROFF': 23278.92, 'SUGAR': 27448.54, 'FD': 1091256.04, 'MIXES': 267983.8, 'SD Gold': 0, 'Breakfast Cereals': 263496.46, 'SD Red': 1311766.14}}},
'TSM1':
{'Tier 3':
{'Традиция':
{'BOXES': 5722.96, 'CONFETTI': 0, 'PURINA': 371448.13, 'CULINARY': 296151.43, 'OTHER DRINKS': 0, 'DG Capsules': 2438.46, 'Cereal bars': 113197.03, 'COUNTLINES': 538179.44, 'TABLETS': 133178.0, 'DG Equipment': 0, 'BISTROFF': 23278.92, 'SUGAR': 27448.54, 'FD': 1091256.04, 'MIXES': 267983.8, 'SD Gold': 0, 'Breakfast Cereals': 263496.46, 'SD Red': 1311766.14}},
'Tier TT':
{'Традиция':
{'BOXES': 5722.96, 'CONFETTI': 0, 'PURINA': 371448.13, 'CULINARY': 296151.43, 'OTHER DRINKS': 0, 'DG Capsules': 2438.46, 'Cereal bars': 113197.03, 'COUNTLINES': 538179.44, 'TABLETS': 133178.0, 'DG Equipment': 0, 'BISTROFF': 23278.92, 'SUGAR': 27448.54, 'FD': 1091256.04, 'MIXES': 267983.8, 'SD Gold': 0, 'Breakfast Cereals': 263496.46, 'SD Red': 1311766.14}}}}
Вот то что хочу получить на выходе из данных файла на примере одного people, т.е. по данному человеку должны быть заполнены только данные в Tier TT:
{'TSM1':
{'Tier 3':
{'Традиция':
{'BOXES': 0, 'CONFETTI': 0, 'PURINA': 0, 'CULINARY': 0, 'OTHER DRINKS': 0, 'DG Capsules': 0, 'Cereal bars': 0, 'COUNTLINES': 0, 'TABLETS': 0, 'DG Equipment': 0, 'BISTROFF': 0, 'SUGAR': 0, 'FD': 0, 'MIXES': 0, 'SD Gold': 0, 'Breakfast Cereals': 0, 'SD Red': 0}},
'Tier TT':
{'Традиция':
{'BOXES': 0, 'CONFETTI': 0, 'PURINA': 0, 'CULINARY': 153362.22, 'OTHER DRINKS': 0, 'DG Capsules': 0, 'Cereal bars': 51489,31, 'COUNTLINES': 463559, 'TABLETS': 46737.20, 'DG Equipment': 0, 'BISTROFF': 0, 'SUGAR': 8280, 'FD': 618453, 'MIXES': 174474, 'SD Gold': 0, 'Breakfast Cereals': 11169, 'SD Red': 1212746,26}}}}
Ответы (1 шт):
Автор решения: MaxU
→ Ссылка
Воспользуйтесь модулем Pandas:
import pandas as pd # pip install pandas
cols = dict(
cat="категория ID",
esr="ESR",
amt="Сумма продаж (руб.)",
stream="Стрим ТК",
tier="Tier",
)
filename = r"D:\download\DOR.xlsx"
df = pd.read_excel(filename)
grp_by = [cols["esr"], cols["tier"], cols["stream"], cols["cat"]]
res = df.groupby(grp_by)[cols["amt"]].sum()
результат в виде Pandas.Series:
In [23]: res
Out[23]:
ESR Tier Стрим ТК категория ID
TSM1 Tier TT Традиция 0 20654.64
Breakfast Cereals 11169.00
COUNTLINES 463559.00
CULINARY 153362.22
Cereal bars 51489.31
FD 1012792.48
MIXES 174474.00
SD Red 1212746.26
SUGAR 8280.00
TABLETS 46737.20
TSM2 Tier 3 Традиция 0 10197.24
BISTROFF 23278.92
BOXES 5722.96
Breakfast Cereals 252327.46
COUNTLINES 74620.44
CULINARY 142789.21
Cereal bars 61707.72
DG Capsules 2438.46
FD 78463.56
MIXES 93509.80
PURINA 371448.13
SD Red 99019.88
SUGAR 19168.54
TABLETS 86440.80
Name: Сумма продаж (руб.), dtype: float64
результат в виде Pandas.DataFrame:
In [24]: res.reset_index()
Out[24]:
ESR Tier Стрим ТК категория ID Сумма продаж (руб.)
0 TSM1 Tier TT Традиция 0 20654.64
1 TSM1 Tier TT Традиция Breakfast Cereals 11169.00
2 TSM1 Tier TT Традиция COUNTLINES 463559.00
3 TSM1 Tier TT Традиция CULINARY 153362.22
4 TSM1 Tier TT Традиция Cereal bars 51489.31
5 TSM1 Tier TT Традиция FD 1012792.48
6 TSM1 Tier TT Традиция MIXES 174474.00
7 TSM1 Tier TT Традиция SD Red 1212746.26
8 TSM1 Tier TT Традиция SUGAR 8280.00
9 TSM1 Tier TT Традиция TABLETS 46737.20
10 TSM2 Tier 3 Традиция 0 10197.24
11 TSM2 Tier 3 Традиция BISTROFF 23278.92
12 TSM2 Tier 3 Традиция BOXES 5722.96
13 TSM2 Tier 3 Традиция Breakfast Cereals 252327.46
14 TSM2 Tier 3 Традиция COUNTLINES 74620.44
15 TSM2 Tier 3 Традиция CULINARY 142789.21
16 TSM2 Tier 3 Традиция Cereal bars 61707.72
17 TSM2 Tier 3 Традиция DG Capsules 2438.46
18 TSM2 Tier 3 Традиция FD 78463.56
19 TSM2 Tier 3 Традиция MIXES 93509.80
20 TSM2 Tier 3 Традиция PURINA 371448.13
21 TSM2 Tier 3 Традиция SD Red 99019.88
22 TSM2 Tier 3 Традиция SUGAR 19168.54
23 TSM2 Tier 3 Традиция TABLETS 86440.80
Чтобы обратиться к определенному значению в Pandas.Series c мультииндексом:
In [37]: res.loc[pd.IndexSlice["TSM1", "Tier TT", "Традиция", "SD Red"]]
Out[37]: 1212746.26
В случае DataFrame можно воспользоваться методом df.query():
tab = res.reset_index() # преобразуем multi-index Series -> DataFrame
q = f'''`{cols["esr"]}` == "TSM1" and `{cols["cat"]}` in ("Cereal bars", "SD Red")'''
In [56]: tab.query(q)
Out[56]:
ESR Tier Стрим ТК категория ID Сумма продаж (руб.)
4 TSM1 Tier TT Традиция Cereal bars 51489.31
7 TSM1 Tier TT Традиция SD Red 1212746.26