基于Pandas实现多用户存提记录的动态时序累计余额计算
解决多用户存提时序统计的冗余与动态列生成问题
看起来你在从单用户扩展到多用户统计时踩了两个坑:一是分组时间维度不统一导致的行数爆炸,二是没有找到动态生成用户列的正确姿势。我来帮你梳理下解决方案:
问题根源分析
你之前分别按Created(存款时间)和Finished(取款时间)分组统计,这两个时间轴的交集/并集会产生大量不必要的组合,直接导致行数从2500暴涨到39万+。而且这种分开统计的方式,很难对齐所有用户的时间维度,后续unstack自然会出问题。
正确的处理流程
我们需要先统一交易的时间维度,再按用户+时间分组,最后动态生成各用户的净变动和累计余额列。
1. 数据预处理:统一交易类型标记
首先把存款和取款记录转换成统一的类型标识(存款记为+1,取款记为-1),避免分开统计:
# 假设df2中,Deposits非空代表存款,Withdrawals非空代表取款 df2['transaction_type'] = df2.apply( lambda row: 1 if pd.notna(row['Deposits']) else -1, axis=1 )
2. 按时间+用户分组统计净变动
用同一个时间字段(比如交易发生时间Created)和用户分组,计算每个时间点每个用户的净存提次数:
# 按时间、用户分组,求和得到净变动(存款次数-取款次数) net_mov_per_user = df2.groupby(['Created', 'name'])['transaction_type'].sum().rename('net_mov')
这一步得到的是一个MultiIndex Series,索引为(Created, name),值为对应时间点该用户的净变动,不会产生冗余行。
3. 计算各用户的累计余额
按用户分组对net_mov做累计求和,得到每个用户的余额变化:
# 按用户维度分组,累计求和得到余额 balance_per_user = net_mov_per_user.groupby('name').cumsum().rename('balance')
4. 动态生成用户列(宽表格式)
用unstack把用户从索引转成列,自动适配所有未知用户:
# 合并净变动和余额,转成宽表格式 final_result = pd.concat([net_mov_per_user, balance_per_user], axis=1).unstack('name')
最终结果会生成多级列:('net_mov', '用户名')和('balance', '用户名'),完美适配n个未知用户的需求。
完整示例代码
import pandas as pd # 模拟多用户数据集 data = { 'Created': ['2024-01-01', '2024-01-01', '2024-01-02', '2024-01-02', '2024-01-03'], 'name': ['Peter', 'Peter', 'Alice', 'Peter', 'Alice'], 'Deposits': [100, None, 200, 150, None], 'Withdrawals': [None, 50, None, None, 80] } df2 = pd.DataFrame(data) df2['Created'] = pd.to_datetime(df2['Created']) # 1. 标记交易类型 df2['transaction_type'] = df2.apply( lambda row: 1 if pd.notna(row['Deposits']) else -1, axis=1 ) # 2. 按时间+用户统计净变动 net_mov_per_user = df2.groupby(['Created', 'name'])['transaction_type'].sum().rename('net_mov') # 3. 计算累计余额 balance_per_user = net_mov_per_user.groupby('name').cumsum().rename('balance') # 4. 动态生成用户列 final_result = pd.concat([net_mov_per_user, balance_per_user], axis=1).unstack('name') print(final_result)
额外优化:填充缺失时间点
如果需要让时序图更连贯,可以用重采样填充缺失值:
# 按天重采样,缺失的净变动填0,余额用前值填充 final_result = final_result.resample('D').asfreq() final_result['net_mov'] = final_result['net_mov'].fillna(0) final_result['balance'] = final_result['balance'].ffill()
这样处理后,你就能直接用这个结果绘制多用户的存提对比时序图了。
内容的提问来源于stack exchange,提问作者klabbaparn
相关产品推荐
相关产品推荐

