【问题标题】:Pandas Expanding Mean with Group By and before current row datePandas 使用 Group By 和当前行日期之前扩展平均值
【发布时间】:2019-04-11 21:51:26
【问题描述】:

我有一个如下的 Pandas 数据框

df = pd.DataFrame([['John', '1/1/2017','10'],
                   ['John', '2/2/2017','15'],
                   ['John', '2/2/2017','20'],
                   ['John', '3/3/2017','30'],
                   ['Sue', '1/1/2017','10'],
                   ['Sue', '2/2/2017','15'],
                   ['Sue', '3/2/2017','20'],
                   ['Sue', '3/3/2017','7'],
                   ['Sue', '4/4/2017','20']
                  ],
                   columns=['Customer', 'Deposit_Date','DPD'])

。在下面的屏幕截图中计算 PreviousMean 列的最佳方法是什么?

该列是该客户今年迄今为止的 DPD 平均值。 IE。包括截至但不包括与当前存款日期匹配的所有 DPD。如果不存在以前的记录,则为 null 或 0。

截图:

注意事项:

  • 数据按客户名称分组,并扩展到存款日期
  • 在每个组中,扩展均值仅使用前几行的值来计算。
  • 在每个新客户开始时,平均值为 0 或 null,因为没有以前的记录可以形成平均值
  • 数据框按客户名称和存款日期排序

【问题讨论】:

标签: python pandas


【解决方案1】:

不是对平均值进行分组和扩展,而是根据条件过滤数据框,并计算 DPD 的平均值:

  • Customer == 当前行的Customer
  • Deposit_Date Deposit_Date

使用df.apply 对数据框中的所有行执行此操作:

df['PreviousMean'] = df.apply(
    lambda x: df[(df.Customer == x.Customer) & (df.Deposit_Date < x.Deposit_Date)].DPD.mean(), 
axis=1)

输出:

  Customer Deposit_Date  DPD  PreviousMean
0     John   2017-01-01   10           NaN
1     John   2017-02-02   15          10.0
2     John   2017-02-02   20          10.0
3     John   2017-03-03   30          15.0
4      Sue   2017-01-01   10           NaN
5      Sue   2017-02-02   15          10.0
6      Sue   2017-03-02   20          12.5
7      Sue   2017-03-03    7          15.0
8      Sue   2017-04-04   20          13.0

【讨论】:

  • 第三个假设是不正确的,但我选择了一个不好的例子是我的错。零点只是新客户的开始,反映了以前没有记录可以形成平均值的事实。或者,它们可以为 Null。
  • @user1761806,请更新您的示例数据和预期输出,因为目前尚不清楚您要达到的目标。 Deposit_Date 是新客户记录的开头吗?如果没有,那么我认为 df['YTD_DPD_Mean'] = df.groupby(['Customer Name']).apply(lambda x: x.shift().expanding().mean()) 就是你所需要的
  • 已按要求更新。目前我仍在努力并尝试其他方法。
  • @user1761806,请将截图替换为文字。请参阅此链接了解如何询问good pandas question
  • 好的,我已经按照链接中的建议提供了 Pandas 代码来生成玩具数据集。
【解决方案2】:

这是从平均值计算中排除重复天数的一种方法:

# create helper series which is NaN for repeated days, DPD otherwise
s = df.groupby(['Customer Name', 'Deposit_Date']).cumcount() == 1
df['DPD2'] = np.where(s, np.nan, df['DPD'])

# apply pd.expanding_mean
df['CumMean'] = df.groupby(['Customer Name'])['DPD2'].apply(lambda x: pd.expanding_mean(x))

# drop helper series
df = df.drop('DPD2', 1)

print(df)

  Customer Name Deposit_Date  DPD  CumMean
0          John   01/01/2017   10     10.0
1          John   01/01/2017   10     10.0
2          John   02/02/2017   20     15.0
3          John   03/03/2017   30     20.0
4           Sue   01/01/2017   10     10.0
5           Sue   01/01/2017   10     10.0
6           Sue   02/02/2017   20     15.0
7           Sue   03/03/2017   30     20.0

【讨论】:

  • 谢谢 - 这并没有达到仅基于当前行之前的日期计算的效果,尽管前 2 行应该显示 0 或 null。但是会玩这个,看看它是否能让我到任何地方。
  • @user1761806,当然,我可能无法完全理解您的问题。您可能必须为每个组添加 DPD = 0 行才能使其按您的意愿工作。
  • 是的,我愿意。在我的示例中,10 = mean(10,10) 和 13.3 = mean (10,10,20)
【解决方案3】:

好的,这是迄今为止我想出的最佳解决方案。

诀窍是首先在客户和存款日期级别创建一个汇总表,其中包含偏移平均值。要计算这意味着您必须先计算总和和计数。

s=df.groupby(['Customer Name','Deposit_Date'],as_index=False)[['DPD']].agg(['count','sum'])
s.columns = [' '.join(col) for col in s.columns]
s.reset_index(inplace=True)

s['DPD_CumSum']=s.groupby(['Customer Name'])[['DPD sum']].cumsum()
s['DPD_CumCount']=s.groupby(['Customer Name'])[['DPD count']].cumsum()
s['DPD_CumMean']=s['DPD_CumSum']/ s['DPD_CumCount']
s['DPD_PrevMean']=s.groupby(['Customer Name'])['DPD_CumMean'].shift(1)

df=df.merge(s[['Customer Name','Deposit_Date','DPD_PrevMean']],how='left',on=['Customer Name','Deposit_Date'])

【讨论】:

    猜你喜欢
    • 2019-03-10
    • 2017-09-21
    • 2014-11-06
    • 1970-01-01
    • 1970-01-01
    • 2018-06-03
    • 1970-01-01
    • 2018-06-27
    • 1970-01-01
    相关资源
    最近更新 更多