我是编码的新手,我正在寻找一种实现以下代码的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工作表。
提前谢谢!
答案 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()