You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

分组值计算并应用至重复行:Pandas DataFrame两列计算的问题排查与实现

解决Pandas DataFrame的两个新列创建问题

先看一下你的原始DataFrame结构:

索引walletpositionposition_rewardsposition_typetoken_sales
00x123SUSHI_LP250Sushi_LP500
00x123ALCX750LP Token500
10xabcGAMMA333.33LP Token750
10xabcFXS666.66LD750

接下来逐个解决你的两个新列需求:


1. 修复position_rewards_pct列的NaN问题

你的原代码问题在于没有按钱包(wallet)分组计算总奖励,而是直接用了整个DataFrame的position_rewards总和,这不仅逻辑不符合需求(你要的是仓位占对应钱包总奖励的比例),还可能因为Decimal类型的运算/广播问题导致NaN。

正确的实现步骤:

  • 先按wallet分组,计算每个钱包的总奖励(用Decimal保证精度)
  • 将分组后的总奖励合并回原DataFrame
  • 计算每个仓位的奖励占比并转换为百分比

示例代码:

from decimal import Decimal

# 1. 按wallet分组计算总奖励(转为Decimal避免精度丢失)
wallet_total = df.groupby('wallet')['position_rewards'].apply(
    lambda x: sum(Decimal(str(val)) for val in x)
).reset_index(name='wallet_total_rewards')

# 2. 合并回原DataFrame
df = df.merge(wallet_total, on='wallet', how='left')

# 3. 计算仓位奖励占比,转为Decimal并保留两位小数
df['position_rewards_pct'] = (
    df.apply(
        lambda row: (Decimal(str(row['position_rewards'])) / row['wallet_total_rewards']) * 100,
        axis=1
    )
).round(2)

运行后,position_rewards_pct列的结果会是:

  • 0x123的SUSHI_LP仓位:25.00%
  • 0x123的ALCX仓位:75.00%
  • 0xabc的GAMMA仓位:33.33%
  • 0xabc的FXS仓位:66.67%

2. 创建token_sales_per_type列

根据需求,我们需要按wallet和position_type计算对应类型的已售token数量,核心逻辑是:该类型的奖励占钱包总奖励的比例 × 钱包的token_sales,并且同一position_type的行重复显示这个值,同时保证所有数值为Decimal类型。

实现步骤:

  • 先按wallet和position_type分组,计算该类型的总奖励
  • 结合之前的钱包总奖励,计算类型占比
  • 乘以token_sales得到该类型的已售数量
  • 合并回原DataFrame,确保同一类型的行重复显示结果

示例代码:

# 1. 按wallet和position_type分组,计算该类型的总奖励
type_total = df.groupby(['wallet', 'position_type'])['position_rewards'].apply(
    lambda x: sum(Decimal(str(val)) for val in x)
).reset_index(name='type_total_rewards')

# 2. 合并钱包总奖励和唯一的token_sales值
type_total = type_total.merge(wallet_total, on='wallet', how='left')
type_total = type_total.merge(df[['wallet', 'token_sales']].drop_duplicates(), on='wallet', how='left')

# 3. 计算该类型的已售数量(Decimal类型)
type_total['token_sales_per_type'] = (
    type_total['type_total_rewards'] / type_total['wallet_total_rewards']
) * type_total['token_sales'].apply(Decimal)

# 4. 合并回原DataFrame
df = df.merge(type_total[['wallet', 'position_type', 'token_sales_per_type']], 
              on=['wallet', 'position_type'], how='left')

运行后,token_sales_per_type列的结果会是:

  • 0x123的SUSHI_LP仓位:125
  • 0x123的ALCX仓位:375
  • 0xabc的GAMMA仓位:250
  • 0xabc的FXS仓位:500

额外注意事项

  • 所有数值转换都用Decimal(str(val)),避免float类型的精度丢失问题
  • 如果你的原始字段已经是Decimal类型,可以直接使用,无需二次转换
  • 可以根据需求用.quantize(Decimal('0.00'))来精确控制小数位数

内容的提问来源于stack exchange,提问作者Luiz Scheuer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 14:27:34