熊猫-遍历列表/字典进行计算

时间:2018-12-17 21:06:21

标签: pandas pandas-groupby

我是编码的新手,我正在寻找一种实现以下代码的pythonic方法。这是带有代码的示例数据框:

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”等)都是对应于多种产品的原材料。例如,“框1”用于“产品1”和“产品2”,“框2”用于“产品3”和“产品4”,“框3”用于“产品5”和“产品6”。

我正在使用的数据集要大得多,但是我将这些数据集存储为列表,例如,我有'Box 1'= ['Prod 1','Prod 2','Prod 3'] 。如果需要,我可以将其存储为包含Box1 = {'Box 1':('Prod 1','Prod 2')-这样的元组的字典-最好。

对于每个分组,我希望计算使用的总盒数,即“已生产” +“报废”库存的总和。为了获得该值,我目前正在对每种产品的分组依据进行手动过滤,并手动进行过滤。您可以看到,我正在手动编写产品列表,作为第二个assign语句。

例如,要计算每个月要从库存中减少的“框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()\

然后,我将不得不为“ Box 2”等做同样笨拙的手册相同的练习。

还有更Python化的方式吗?我想每个月完成此分析。实际数据要复杂得多,大约有20个不同的“盒子”,每个盒子都有不同数量的产品。我不确定是否应该创建函数或使用字典还是列表,但在此过程中会有所帮助。作为最后一个请求,我希望能够灵活地将每个“ Box_1”写入不同的Excel工作表。

提前谢谢!

3 个答案:

答案 0 :(得分:3)

我想我会向下过滤源数据框,只是希望先查询一下,然后再进行分组和聚集:

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

答案 1 :(得分:3)

不确定最后要如何获得结果,但是由于每个Prod仅使用一个Box,因此您可以replace用{{1 }},然后像您一样执行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}

答案 2 :(得分:0)

我不明白为什么需要这么长的表达。如果我没有完全错的话,看来您只关心满足条件的行总数。

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()