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

能否在Pandas中对Motelling信号平滑方法进行向量化实现?

向量化实现Motelling信号平滑方法

当然可以实现向量化的Motelling函数应用!不过因为这个响应规则依赖前一时刻的输出值(属于带状态的递推逻辑),直接用普通的元素级向量化操作会有点棘手,但我们有几种高效的方式能避开逐行循环,提升处理速度。

方法1:用Numba实现编译后的递推(首推,适配大规模数据)

Numba能把Python循环编译成机器码,效率直逼原生向量化操作,还能完美处理这种带状态的逻辑。写个简单函数加个装饰器就行:

import numba
import pandas as pd
import numpy as np

@numba.jit(nopython=True)
def motelling_numba(signal):
    n = len(signal)
    output = np.zeros(n, dtype=np.int8)
    for i in range(n):
        if i == 0:
            # 初始时刻无前置输出,按规则直接判断
            if signal[i] == 1:
                output[i] = -1
            elif signal[i] == 5:
                output[i] = 1
            else:
                output[i] = 0
        else:
            prev_out = output[i-1]
            if signal[i] == 1 or (signal[i] == 2 and prev_out == -1):
                output[i] = -1
            elif signal[i] == 5 or (signal[i] == 4 and prev_out == 1):
                output[i] = 1
            else:
                output[i] = 0
    return output

# 假设你的DataFrame是df,信号列名为'S'
df['F'] = motelling_numba(df['S'].values)

这个方法看起来是循环,但Numba编译后会以接近向量化的速度运行,比纯Python循环快几个数量级,非常适合处理大规模时间序列。

方法2:纯Pandas累积操作(适配小规模数据)

如果不想额外引入Numba,用Pandas自带的累积操作也能搞定。不过这种方法本质还是逐行处理,数据量大了速度会跟不上,适合小规模数据集:

def motelling_state(prev_state, current_s):
    prev_out = prev_state
    if current_s == 1 or (current_s == 2 and prev_out == -1):
        return -1
    elif current_s == 5 or (current_s == 4 and prev_out == 1):
        return 1
    else:
        return 0

# 初始化第一个输出值
first_val = -1 if df['S'].iloc[0] == 1 else 1 if df['S'].iloc[0] == 5 else 0
# 累积应用状态函数生成后续值
df['F'] = [first_val]
for s in df['S'].iloc[1:]:
    df['F'].append(motelling_state(df['F'].iloc[-1], s))

方法3:向量化条件+循环(折中方案,适配中等规模数据)

要是你想尽量用向量化的条件判断,也可以结合前一时刻的输出值做批量判断,虽然还是要按顺序循环,但比纯Python循环效率高一些:

df['F'] = 0
# 初始化第一个值
df.loc[0, 'F'] = -1 if df['S'].iloc[0] == 1 else 1 if df['S'].iloc[0] == 5 else 0

# 按顺序更新后续行
for i in range(1, len(df)):
    prev_f = df['F'].iloc[i-1]
    # 用向量化条件判断当前行的输出
    is_neg = (df['S'].iloc[i] == 1) | ((df['S'].iloc[i] == 2) & (prev_f == -1))
    is_pos = (df['S'].iloc[i] == 5) | ((df['S'].iloc[i] == 4) & (prev_f == 1))
    
    if is_neg:
        df.loc[i, 'F'] = -1
    elif is_pos:
        df.loc[i, 'F'] = 1
    else:
        df.loc[i, 'F'] = 0

最后总结下选择建议:

  • 大规模时间序列:首推Numba编译的方法,代码简洁还跑得快;
  • 纯Pandas生态下的小规模数据:用累积操作方法就行;
  • 中等规模数据:试试向量化条件+循环的折中方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:57:31