如何用向量化方式基于累计值计算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
相关产品推荐
相关产品推荐

