Python 熊猫-迭代列表/字典进行计算

Python 熊猫-迭代列表/字典进行计算,python,pandas,pandas-groupby,Python,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([

我对编码是新手&我正在寻找一种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={'Box1':('prod1','prod2')-任何最好的

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

例如,要计算每月从库存中释放多少“箱子1”,您需要将生产和报废的“箱子1”的值相加。然后,您需要计算“产品1”到“产品3”的值(因为它们使用“箱子1”)生产和报废的,并将它们加在一起,得到每个时间段使用和报废的总“盒子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”,等等

有没有更具python风格的方法?我希望以后每个月都能完成这项分析。实际数据要复杂得多,大约有20个不同的“盒子”,每个盒子都有不同数量的产品。我不确定我是否应该创建一个函数或使用字典与列表,但如果有任何帮助,我将不胜感激还有很长的路要走。作为最后一个请求,我希望能够灵活地将这些“方框1”写入不同的excel工作表


提前感谢!

我想我会过滤我的源数据帧,只想首先查询,然后进行分组和聚合:

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

不确定最后的结果是什么,但由于每个
Prod
只使用一个
,因此您可以通过其
Prod
进行操作,并像您一样执行
groupby
。假设您有一个字典,例如:

box_dict = {'Box 1': ('Prod 1', 'Prod 2'), 
            'Box 2': ('Prod 3', 'Prod 4'), 
            'Box 3': ('Prod 5', 'Prod 6')}
然后,您需要将其反转,以将
prod
作为键,将
作为值:

dict_prod = { prod:box for box, l_prod in box_dict.items() for prod in l_prod}
现在您可以使用
替换

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

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

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

你的groupby代码块中的
idx
是什么?对不起-我在任何时候使用.loc.我都应该在上面声明idx=pd.indexlice。我现在已经在上面添加了它。谢谢你看一看!一个
Prod X
可以使用两个
框Y
?@Ben.T是的。基本上,任何“框Z”都会有多个产品分配给它。@Ben.T很抱歉造成混淆n-我的错!不,每个产品只使用一个盒子。Prod 2只使用盒子1,而不使用其他盒子。很好地使用字典替换来捕获更多盒子。+1谢谢Ben!这个解决方案非常灵活,对于我的数据结构来说非常好。我需要做更多的测试,但这看起来很好。再次感谢。@keg5038 Ben.T解决方案更好,而且更好采取了我认为你在寻找的额外步骤。