Python 如何编写一个有效的函数来计算给定时间段内不同账户的平均期末余额

Python 如何编写一个有效的函数来计算给定时间段内不同账户的平均期末余额,python,pandas,function,statistics,Python,Pandas,Function,Statistics,我在一家金融机构工作。在我们的交易表中,我们只在客户进行交易时跟踪他们的余额。例如,如果客户在10月1日开立了一个账户,账户金额为200美元,然后在10月8日提取了50美元,那么他在交易表中只有两个条目,一个用于2020/10/01,另一个用于2020/10/8。现在,这个问题的焦点是期末余额。按照这个类比,如果我们使用今天作为截止日期,您会同意客户7天(2020/10/8-2020/10/1)的期末余额为200美元,其余29天的期末余额为150美元 现在,我不知道如何编写这个函数。我一直遇到错

我在一家金融机构工作。在我们的交易表中,我们只在客户进行交易时跟踪他们的余额。例如,如果客户在10月1日开立了一个账户,账户金额为200美元,然后在10月8日提取了50美元,那么他在交易表中只有两个条目,一个用于2020/10/01,另一个用于2020/10/8。现在,这个问题的焦点是期末余额。按照这个类比,如果我们使用今天作为截止日期,您会同意客户7天(2020/10/8-2020/10/1)的期末余额为200美元,其余29天的期末余额为150美元

现在,我不知道如何编写这个函数。我一直遇到错误,如果有人能帮我解决python代码和相应的注释,我将不胜感激,以便这成为我一次有效的学习经验

这是我拥有的数据集示例:

sample_df = pd.DataFrame({'ID': [15, 16, 15, 15, 16, 17, 17, 16],
                         'Calendar_Date': ['2020-10-10', '2020-10-12', '2020-10-12', '2020-10-22', '2020-10-28', '2020-10-30', '2020-11-03', '2020-11-04'] ,
                         'Closing_Balance': [10000, 3000, 6000, 5100, 14500, 25000, 13000, 9000]}) 
这就是我所期望的结果:

result_df = pd.DataFrame({'ID':[15, 16, 17],
                         'Total_Days': [26, 24, 6],
                         'Average_Account_Balance': [5823.08, 6375.00, 19000]})
为清楚起见:我就是这样得出结果的:

当ID=15时,总天数=(2+10+15)=27; 平均账户余额=(10000*2)+(6000*10)+(5100*15))/27=156500/27=5796.3

当ID=16时,总天数=(16+7+2)=25; 平均账户余额=(3000*16)+(14500*7)+(9000*2))/25=167500/25=6700.00

当ID=17时,总天数=(4+3)=7
平均账户余额=((25000*4)+(13000*3))/7=139000/7=19857.14


我需要的解决方案是计算效率高,因为你可以猜出多少交易,我们在我们的数据库。如果您对此处所述或暗示的内容不清楚,请随时提问。谢谢大家!

您可以将此问题分解为几个步骤。首先,我们需要在dataframe中创建一些新列:

  • 查找从每个日期到结束日期的天数(在您的示例中为今天)
  • 在每组
    “ID”
    中,获取先前计算列之间的差值,以获取交易之间的天数。然后,我们使用
    fillna
    方法来填充剩余的日期差异(例如,通过使用
    diff
    我们可以得到行之间的差异,但是我们忽略了
    “ID”
    中最近日期与今天日期之间的差异)。这为我们建立了一个适当的
    “交易间隔天数”
  • 计算加权余额列:只需将
    “期末余额”乘以新创建的
    “交易间隔天数”列即可
  • 现在我们已经创建了额外的列,我们可以执行一个
    groupby->aggregation
    操作来获得
    加权余额列的
    ,并将其除以每个唯一的
    “ID”

    我注意到我们的结果有轻微的差异,我相信这可能是由于我们的时区不同(我今天是2020年11月6日,不确定您的时间/天),所以我们的“总天数”可能不同


    另外,如果您的数据非常大,我建议您使用
    DataFrame.eval
    执行算术运算。

    您好,Cameron,谢谢。我们也有相同的日期,即2020年11月6日,但我认为您今天考虑的是不应该考虑的,因为我们不知道今天是否有任何客户进行交易。这应该是一种T-1或D-1类型的情况。你好@Cameron Riddell,我计算的时候太累了,这影响了我的数字。是的,你的解决方案奏效了。非常感谢你!我将编辑我的问题,这样将来它就不会误导任何人。太棒了!既然这似乎对您有效,您是否介意选择正确的答案,以便其他有类似问题的人能够快速找到解决方案?很好,完成了!
    sample_df["days_from_today"] = (pd.to_datetime("11/06/2020").normalize() - sample_df["Calendar_Date"]).dt.days
    
    sample_df["days_between_transactions"] = (sample_df.groupby("ID")["days_from_today"]
                                              .diff(-1)
                                              .fillna(sample_df["days_from_today"])
                                              .astype(int))
    
    sample_df["weighted_balance"] = sample_df["Closing_Balance"] * sample_df["days_between_transactions"]
    
    print(sample_df)
       ID Calendar_Date  Closing_Balance  days_from_today  days_between_transactions  weighted_balance
    0  15    2020-10-10            10000               27                          2             20000
    1  16    2020-10-12             3000               25                         16             48000
    2  15    2020-10-12             6000               25                         10             60000
    3  15    2020-10-22             5100               15                         15             76500
    4  16    2020-10-28            14500                9                          7            101500
    5  17    2020-10-30            25000                7                          4            100000
    6  17    2020-11-03            13000                3                          3             39000
    7  16    2020-11-04             9000                2                          2             18000
    
    aggregated_df = sample_df.groupby("ID").agg(
        weighted_total_account_balance=("weighted_balance", "sum"), 
        total_days=("days_from_today", "max")
    )
    
    aggregated_df["average_account_balance"] = aggregated_df["weighted_total_account_balance"] / aggregated_df["total_days"]
    
    print(aggregated_df)
        weighted_total_account_balance  total_days  average_account_balance
    ID                                                                     
    15                          156500          27              5796.296296
    16                          167500          25              6700.000000
    17                          139000           7             19857.142857