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

如何用向量化方式基于累计值计算DataFrame列值?

解决Pandas递推计算Balance、Size、Profit的问题

你的核心问题在于Balance和Size(即Quantity)是递推依赖关系:每一行的Size依赖上一行的Balance,而当前行的Balance又依赖当前行的Profit(由Size计算而来)。这种场景下,Pandas的向量化操作(比如shift)无法直接生效,因为向量化操作是基于列的初始值批量计算,无法动态引用上一步的计算结果。

直接可行的循环实现

对于中等规模的数据集(几万行以内),直接用循环遍历计算是最直观且有效的方案:

import pandas as pd

# 确保首行Balance初始值正确
best['Balance'].iloc[0] = 100000

# 从第二行开始遍历计算
for idx in range(1, len(best)):
    # 获取上一行的Balance
    prev_balance = best['Balance'].iloc[idx-1]
    # 获取当前行的参数
    current_buy = best['Buy'].iloc[idx]
    current_n = best['N'].iloc[idx]
    current_ret = best['Ret'].iloc[idx]
    
    # 计算Size(即Quantity)并取整
    quantity = (prev_balance / current_buy / current_n).round(0)
    best['Size'].iloc[idx] = quantity
    
    # 计算Profit
    profit = quantity * current_ret * current_buy
    best['Profit'].iloc[idx] = profit
    
    # 更新当前行的Balance
    best['Balance'].iloc[idx] = prev_balance + profit

大数据量下的加速方案

如果你的数据集规模很大(百万级别),可以用numba对循环进行JIT编译加速,性能会比纯Python循环提升几十倍:

from numba import jit
import numpy as np

# 定义numba加速的递推函数
@jit(nopython=True)
def compute_portfolio(balance_arr, buy_arr, n_arr, ret_arr):
    for i in range(1, balance_arr.shape[0]):
        prev_bal = balance_arr[i-1]
        buy = buy_arr[i]
        n = n_arr[i]
        ret = ret_arr[i]
        
        quantity = np.round(prev_bal / buy / n)
        profit = quantity * ret * buy
        balance_arr[i] = prev_bal + profit
    return balance_arr

# 将DataFrame列转为numpy数组(numba对numpy数组优化更好)
balance_arr = best['Balance'].values
balance_arr[0] = 100000  # 初始化首行Balance

# 调用加速函数计算Balance
balance_arr = compute_portfolio(balance_arr, best['Buy'].values, best['N'].values, best['Ret'].values)

# 将计算结果放回DataFrame
best['Balance'] = balance_arr

# 批量计算Size和Profit(此时Balance已完成递推,可直接用shift)
best['Size'] = (best['Balance'].shift(1) / best['Buy'] / best['N']).round(0)
best['Profit'] = best['Size'] * best['Ret'] * best['Buy']

为什么你的原始代码无法运行?

你尝试用shift()来获取上一行Balance,但best['Balance'].shift(1)引用的是初始状态下的Balance列,而非动态更新后的Balance值。当你后续更新Balance列时,shift操作并不会重新计算,导致所有行的Size都基于初始的100000计算,最终结果完全错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 08:10:31