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

如何优化DataFrame列移位计算斜率生成新列的低效代码?

优化Python Pandas斜率计算代码的性能问题

我需要优化一段Python代码,实现以下功能:

  • 将DataFrame的指定列移位x次,让每行包含x个历史值
  • 结合当前行的值组成数组,计算线性回归斜率
  • 将斜率存入对应的新列

原代码可运行但效率极低,处理1万行数据耗时约30秒,原代码如下:

from datetime import datetime

import math
import pandas as pd
import numpy as np

def trending(row, label, amt, prepend = False, postpend = False, reverse = True):
    arr = []

    if prepend:
        arr.append(row[label])

    for i in range(amt):
        arr.append(row[f'{label}_{i}'])

    if postpend:
        arr.append(row[label])

    if reverse:
        arr.reverse()

    if any(x == None or math.isnan(x) for x in arr):
        return 0

    return slope(arr)

def slope(arr):
    if len(arr) <= 1:
        return 0
    coeffs = np.polyfit(range(len(arr)), arr, 1)
    slope = coeffs[-2]
    return float(slope)

def trends(df):
    start = datetime.now()

    look_back = 5

    for i in range(look_back):
        j = i + 1
        df2 = df[['close', 'pvi', 'nvi', 'smi', 'roc', 'macd', 'histogram', 'percent_b', 'height']]
        df2 = df2.add_suffix(f'_{i}')
        df2 = df2.shift(j)
        df = pd.concat([df, df2], axis=1)

    def close_trend(row):
        return trending(row, 'close', look_back, True, False)

    def pvi_trend(row):
        return trending(row, 'pvi', look_back, True, False)

    def nvi_trend(row):
        return trending(row, 'nvi', look_back, True, False)

    def smi_trend(row):
        return trending(row, 'smi', look_back, True, False)

    def macd_trend(row):
        return trending(row, 'macd', look_back, True, False)

    def roc_trend(row):
        return trending(row, 'roc', look_back, True, False)

    def histogram_trend(row):
        return trending(row, 'histogram', look_back, True, False)

    def percent_b_trend(row):
        return trending(row, 'percent_b', look_back, True, False)

    def height_trend(row):
        return trending(row, 'height', look_back, True, False)
    
    df['close_trend'] = df.apply(close_trend, axis=1)
    df['pvi_trend'] = df.apply(pvi_trend, axis=1)
    df['nvi_trend'] = df.apply(nvi_trend, axis=1)
    df['smi_trend'] = df.apply(smi_trend, axis=1)
    df['macd_trend'] = df.apply(macd_trend, axis=1)
    df['roc_trend'] = df.apply(roc_trend, axis=1)
    df['histogram_trend'] = df.apply(histogram_trend, axis=1)
    df['percent_b_trend'] = df.apply(percent_b_trend, axis=1)
    df['height_trend'] = df.apply(height_trend, axis=1)

    print(f'Trends function took {datetime.now() - start}')

    return df

data = []

for i in range(10000):
    data.append([545.9, 0.3333398862,   0.01673619117,  0.2111060119,   55.95725508,    1.100447539,    0.8652411735,   0.8219623901,   1.808441041,    46.79554862])

columns = ['close', 'macd', 'histogram', 'roc', 'rsi', 'pvi', 'nvi', 'percent_b', 'height', 'smi']

df = pd.DataFrame(columns=columns, data=data)

df = trends(df)

print(df)

优化后的代码

from datetime import datetime
import pandas as pd
import numpy as np

def trends_optimized(df):
    start = datetime.now()
    look_back = 5
    target_cols = ['close', 'pvi', 'nvi', 'smi', 'roc', 'macd', 'histogram', 'percent_b', 'height']
    
    # 预计算x轴值,避免重复创建
    x = np.arange(look_back + 1)
    
    # 向量化斜率计算函数
    def calc_slope(window):
        if np.isnan(window).any():
            return 0.0
        coeffs = np.polyfit(x, window, 1)
        return coeffs[0]
    
    for col in target_cols:
        # 滚动窗口包含当前行+前look_back行
        rolling_window = df[col].rolling(window=look_back+1, min_periods=look_back+1)
        # raw=True直接传递numpy数组,提升效率
        df[f'{col}_trend'] = rolling_window.apply(calc_slope, raw=True)
        # 填充窗口不足的行(前look_back行)为0
        df[f'{col}_trend'] = df[f'{col}_trend'].fillna(0.0)
    
    print(f'Trends function took {datetime.now() - start}')
    return df

# 测试数据
data = []
for i in range(10000):
    data.append([545.9, 0.3333398862, 0.01673619117, 0.2111060119, 55.95725508, 
                 1.100447539, 0.8652411735, 0.8219623901, 1.808441041, 46.79554862])
columns = ['close', 'macd', 'histogram', 'roc', 'rsi', 'pvi', 'nvi', 'percent_b', 'height', 'smi']
df = pd.DataFrame(columns=columns, data=data)

df = trends_optimized(df)
print(df)

核心优化点

  • 替换逐行操作:用rolling.apply(raw=True)替代df.apply(axis=1),利用Pandas向量化特性大幅提升效率
  • 简化移位逻辑:直接使用滚动窗口rolling,避免手动创建移位列和多次concat,减少内存开销
  • 消除重复代码:统一遍历所有目标列,移除重复的单列处理函数
  • 预计算公共数据:提前生成x轴数组,避免每次计算斜率时重复创建
  • 高效空值处理:用np.isnan批量判断空值,替代逐元素检查

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 06:28:17