Панды - перебирайте списки / словари для расчетов - PullRequest
0 голосов
/ 18 декабря 2018

Я новичок в кодировании и ищу питонский способ реализации следующего кода.Вот примерный кадр данных с кодом:

np.random.seed(1111)
df2 = pd.DataFrame({
'Product':np.random.choice( ['Prod 1','Prod 2','Prod 3', 'Prod 4','Prod 5','Prod 6','Box 1','Box 2','Box 3'], 10000),
'Transaction_Type': np.random.choice(['Produced','Transferred','Scrapped','Sold'], 10000),
'Quantity':np.random.randint(1,100, size=(10000)),
'Date':np.random.choice( pd.date_range('1/1/2017','12/31/2018',  
                      freq='D'), 10000)})
idx = pd.IndexSlice

В наборе данных каждый «ящик» («Ящик 1», «Ящик 2» и т. Д.) Является сырьем, которое соответствует нескольким продуктам.Например, «Box 1» используется для «Prod 1» и «Prod 2», «Box 2» используется для «Prod 3» и «Prod 4», а «Box 3» используется для «Prod 5» &«Прод 6».

Набор данных, с которым я работаю, намного больше, но у меня эти наборы данных хранятся в виде списков, например, у меня 'Box 1' = ['Prod 1', 'Prod 2', 'Prod3' ].При необходимости я мог бы хранить в виде словаря с кортежем типа Box1 = {'Box 1' :( 'Prod 1', 'Prod 2') - что угодно, что лучше.

Для каждой группы я рассчитываю рассчитать общее количество используемых ящиков, которое является суммой произведенных + списанных запасов.Чтобы получить это значение, в настоящее время я делаю ручной фильтр по группам каждого продукта и вручную.Вы можете видеть, что я вручную пишу список продуктов в качестве второго оператора присваивания.

Например, чтобы подсчитать, сколько «Бокса 1» необходимо извлечь из инвентаря, каждый месяц вы должны суммировать значения «Бокса 1», которые были произведены и сданы на слом.Затем вы должны рассчитать значения от «Prod 1» до «Prod 3» (поскольку они используют «Box 1»), которые были произведены и сданы в лом, и сложить их все вместе, чтобы получить общее значение «Box 1», использованное и утилизированное для каждого разаРамка.Вот пример того, что я сейчас делаю:

box1 = ['Box 1','Prod 1','Prod 2']
df2[df2['Transaction_Type'].isin(['Produced','Scrapped'])].groupby([pd.Grouper(key='Date',freq='A' ),'Product','Transaction_Type']).agg({'Quantity':'sum'})\
    .unstack()\
    .loc[idx[:,box1],idx[:]]\
    .assign(Box_1 = lambda x: 'Box 1')\
    .assign(List_of_Products = lambda x: 'Box 1, Prod 1, Prod 2')\
    .reset_index()\
    .set_index(['Box_1','List_of_Products','Date','Product'])\
    .groupby(level=[0,1,2]).sum()\

Затем я должен был бы выполнить то же самое неуклюжее ручное то же упражнение для «Коробки 2» и т. Д.

Есть либолее питонический способ?Я хотел бы завершить этот анализ каждый месяц вперед.Фактические данные намного сложнее, примерно с 20 различными «блоками», которые имеют различное количество продуктов, связанных с каждым.Я не уверен, стоит ли мне искать создание функции или использовать словарь или списки, но я был бы признателен за любую помощь на этом пути.В качестве последнего запроса я хотел бы иметь возможность записать каждый из этих «Box_1» на другой лист Excel.

Заранее спасибо!

Ответы [ 3 ]

0 голосов
/ 18 декабря 2018

Не уверен, как вы хотите, чтобы результат в конце, но так как каждый Prod использует только один Box, то вы можете replace Prod его Box и сделатьgroupby, как вы делаете.Предположим, у вас есть словарь, например:

box_dict = {'Box 1': ('Prod 1', 'Prod 2'), 
            'Box 2': ('Prod 3', 'Prod 4'), 
            'Box 3': ('Prod 5', 'Prod 6')}

, затем вы хотите изменить его на обратный, чтобы получить prod в качестве ключа и box в качестве значения:

dict_prod = { prod:box for box, l_prod in box_dict.items() for prod in l_prod}

Теперь вы можете использовать replace:

print (df2[df2['Transaction_Type'].isin(['Produced','Scrapped'])]
          .replace({'Product':dict_prod}) #here to change the prod to the box used
          .groupby([pd.Grouper(key='Date',freq='A' ),'Product','Transaction_Type'])['Quantity']
          .sum().unstack())
                    Quantity         
Transaction_Type   Produced Scrapped
Date       Product                  
2017-12-31 Box 1      20450    19152
           Box 2      20848    21145
           Box 3      22475    21518
2018-12-31 Box 1      19404    16964
           Box 2      21655    20753
           Box 3      21343    21576
0 голосов
/ 18 декабря 2018

Я не понимаю, зачем нужно такое длинное выражение.Кажется, вам важно только общее количество строк, удовлетворяющих условию, если я не ошибаюсь.

d = {'Box 1': ('Box 1', 'Prod 1', 'Prod 2')}
d_type = {'Box 1': ('Produced', 'Scrapped')}
selected = df2[df2['Product'].isin(d['Box 1']) & df2['Transaction_Type'].isin(d_type['Box 1'])]
print(len(selected))

Для ваших потребностей экспорта в Excel будет работать что-то, показанное ниже.

writer = pd.ExcelWriter("test.xlsx")
selected.to_excel(writer, 'Sheet1')
writer.save()
0 голосов
/ 18 декабря 2018

Я думаю, что я бы отфильтровал исходный фрейм данных, чтобы просто захотел, чтобы мне сначала нужно было выполнить запрос, а затем группировать и объединять:

df2.query('Transaction_Type in ["Produced","Scrapped"] and Product in ["Box 1","Prod 1","Prod 2"]')\
   .groupby([pd.Grouper(key='Date',freq='A'),'Product','Transaction_Type'])['Quantity'].sum()\
   .unstack().reset_index(level=1).groupby(level=0).agg({'Product':lambda x: ', '.join(x),'Produced':'sum','Scrapped':'sum'})

Вывод:

                          Product  Produced  Scrapped
Date                                                 
2017-12-31  Box 1, Prod 1, Prod 2     20450     19152
2018-12-31  Box 1, Prod 1, Prod 2     19404     16964
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...