如何在Python中找到每个时刻过去52周销售额的平均值

3
我有一个csv文件,包含四列数据:日期、批发商、产品和销售额。我想要找到每个日期下产品和批发商组合的过去52周平均销售额。这意味着在过去的52周中,产品'A'在批发商'B'处于时间'C'时的平均历史销售额是多少。 例如,我们知道产品'A'在批发商'B'处于1月、4月、5月、8月的销售额分别为100、200、300、400。假设我们在1月之前没有任何记录。因此,在4月份时,产品'A'在批发商'B'处的历史平均销售额等于100/1,在5月份时等于(200+100)/2,在8月份时等于(300+200+100)/3。
以下是我的数据表格:
date    wholesaler product  sales
12/31/2012  53929  UPE54     4
12/31/2012  13131  UPE55     1
2/23/2013   13131  UPE55  1156
4/24/2013   13131  UPE55     1
12/1/2013   83389  UPE54     9
12/17/2013  83389  UPE54     1
12/18/2013  52237  UPE54     9
12/19/2013  53929  UME24     1
12/31/2013  82204  UPE55     9
12/31/2013  11209  UME24     4
12/31/2013  52237  UPE54     1

现在我正在使用:

df = pd.read_csv('Sample.csv',index_col='date')

expd_gb = df.reset_index().groupby(['wholesaler', 'product'])['sales'].apply(pd.Series.expanding)
idx = df.reset_index().groupby(['wholesaler', 'product', 'date'])['sales'].count().index

cnct = pd.concat([expd_gb.iloc[n].mean().shift(1) for n in range(len(expd_gb))])
cnct.index = idx

这给出了每个产品-批发商组合的先前销售总平均值(不是过去52周的平均值)。结果如下:

wholesaler  product  date      
11209       UME24    12/31/2013      NaN
13131       UPE55    12/31/2012      NaN
                     2/23/2013       1.0
                     4/24/2013     578.5
52237       UPE54    12/18/2013      NaN
                     12/31/2013      9.0
53929       UME24    12/19/2013      NaN
            UPE54    12/31/2012      NaN
82204       UPE55    12/31/2013      NaN
83389       UPE54    12/1/2013       NaN
                     12/17/2013      9.0   

随着时间的推移,销售记录的迭代不断增加。我需要找出过去52周内销售额的平均值。也就是说,在某个日期(例如2015年11月6日),特定批发商的某个产品在过去52周内的平均销售额是多少。非常感谢您的帮助!
2个回答

2
考虑一个应用函数,它会有条件地为每个记录的批发商和产品平均计算过去52周的销售。如果没有解决方法,groupby() 函数将返回相同的组值,而你需要一种运行组平均值。因此,尝试通过系列处理来解决该问题。确保将日期转换为日期时间格式,因为你可以使用 timedelta() 函数倒数52周。
import pandas as pd
import datetime

dateparse = lambda x: pd.datetime.strptime(x, '%m/%d/%Y')

df = pd.read_csv('Sample.csv', index_col='date',
                 parse_dates=[0], date_parser=dateparse)

def last52weeks(x):
    ser = df['sales'][(df.index >= x.name - datetime.timedelta(weeks=52)) &
                      (df.index <= x.name) &
                      (df['wholesaler'] == x[0]) &
                      (df['product'] == x[1])]
    return ser.mean()

df['avg_sales_last52weeks'] = df.apply(last52weeks, axis=1)
df = df.sort_values(['wholesaler', 'product'])

#             wholesaler product  sales    avg_sales_last52weeks
# date                                                          
# 2013-12-31       11209   UME24      4                      4.0
# 2012-12-31       13131   UPE55      1                      1.0
# 2013-02-23       13131   UPE55   1156                    578.5
# 2013-04-24       13131   UPE55      1                    386.0
# 2013-12-18       52237   UPE54      9                      9.0
# 2013-12-31       52237   UPE54      1                      5.0
# 2013-12-19       53929   UME24      1                      1.0
# 2012-12-31       53929   UPE54      4                      4.0
# 2013-12-31       82204   UPE55      9                      9.0
# 2013-12-01       83389   UPE54      9                      9.0
# 2013-12-17       83389   UPE54      1                      5.0

非常感谢!太棒了!你认为timedelta()函数能否更快地工作?实际上,我需要计算超过2500万行数据,并希望找到最快的方法来得出结果。再次感谢您优雅的代码! - Ashkan Mirzaee
1
哇!数据集相当大。考虑使用条件聚合查询的数据库SQL解决方案来运行平均值和日期索引表,然后导入到pandas df中。 - Parfait

1
如果平均数是每周的平均数,那么你应该将总和(每个产品每个批发商)除以周数,即52,而不是通过cnct = pd.concat([expd_gb.iloc[n].mean().shift(1) for n in range(len(expd_gb))])得到平均值。如果你少于52周,则希望将该产品的总销售额除以你拥有的周数。例如,如果在(2016年)1月份你卖了100个小部件,在2月份卖了200个,在3月份卖了400个,截至4月1日,你的总销售额为700。1月有31天,2月有29天,3月有31天,因此总天数为91,恰好为13周(91/7)。因此,这三个月期间的平均每周销售额为700/13或约为53.85个小部件每周。无论你有91个日记录,13个周记录还是3个月记录,平均每周销售额仍然相同。
要获取天数(以及其中的周数),可以查看timedelta对象。一旦超过52周,您还可以使用timedelta来计算52周(或364天)前的日期,并在阅读文件时丢弃该日期之前的任何内容。

谢谢您的评论!这有点复杂。在第一年中,由于每个产品每个批发商的记录少于52条,我们可以使用所有记录的平均值,但对于接下来的几年,我们只需要寻找过去52周的平均值。此外,并非所有产品-批发商组合都有每周记录,这意味着对于某个产品-批发商,例如我们有12条记录,因此平均值应为sum(12 records)/ 52。实际上,我认为您的评论是正确的,但我不知道如何实现这个逻辑! - Ashkan Mirzaee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接