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

如何为序列末端实现带收缩窗口的pct_change百分比变化计算?

解决分组内收缩窗口的百分比变化计算问题

我明白你的需求:要按label分组计算价格的百分比变化,窗口周期是3,而且当分组序列末端没有足够的后续数据时,要用分组的最后一个价格来计算收缩窗口的变化率,而不是留空NaN。原代码的问题在于pct_change(3)是固定窗口逻辑,当末端没有足够数据时就会生成NaN,且shift(-3)也没处理收缩窗口的场景。

高效的向量化解法

考虑到你数据量较大,我们用向量化操作实现,避免逐元素循环,保证运行效率。核心思路是:对每个分组的价格序列,给每个位置计算对应的目标索引——如果当前位置往后数3个元素存在,就用那个元素;如果不存在,就用分组的最后一个元素。然后直接计算百分比变化。

完整代码如下:

import pandas as pd
import numpy as np

labels = ['A', 'A', 'A', 'A', 'A', 'B', 'A', 'C', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'B']
prices = [62, 55, 55, 74, 31, 77, 20, 21, 25, 30, 21, 35, 66, 12, 1, 2, 4]
df = pd.DataFrame(data={'label': labels, 'price': prices}, columns=['label', 'price'])

# 先按label分组排序,同label内保留原索引顺序(和你原代码逻辑一致)
df = df.iloc[np.lexsort((df.index, df['label'].values))]

def rolling_pct_change(arr, window=3):
    n = len(arr)
    # 计算每个位置的目标索引:如果i+window在序列内就用i+window,否则用最后一个元素的索引
    target_indices = np.minimum(np.arange(n) + window, n - 1)
    # 计算百分比变化:(目标价格 / 当前价格) - 1
    return (arr.iloc[target_indices].values / arr.values) - 1

# 分组应用自定义函数,生成price_chg列
df['price_chg'] = df.groupby('label')['price'].transform(rolling_pct_change, window=3)

print(df)

代码细节解释

  1. 排序处理:和你原代码逻辑一致,用np.lexsort把同label的行聚合在一起,同时保留原数据的索引顺序,保证分组内的价格序列符合原始顺序。
  2. 自定义函数rolling_pct_change:
    • 用np.arange(n)生成每个元素的位置索引,加上窗口大小3得到初始目标位置;
    • 用np.minimum把超出序列长度的目标位置替换为最后一个元素的索引(n-1),完美实现收缩窗口的需求;
    • 全程向量化计算,比循环快几个数量级,适合大数据场景。
  3. 分组应用:用groupby.transform把函数批量应用到每个分组,直接生成对应列,不需要额外的合并操作,代码简洁高效。

验证效果(以A组为例)

A组的价格序列为[62,55,55,74,31,20]:

  • 索引3(价格74):往后3个位置超出序列长度,用最后一个价格20计算,变化率为(20/74)-1≈-0.7297;
  • 索引4(价格31):同样用最后一个价格20,变化率为(20/31)-1≈-0.3548;
  • 索引5(价格20):用自身计算,变化率为0;
    这些位置都不会再出现NaN,完全符合你的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:51:07