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

如何检测某一Pandas时间序列是否按序存在于另一长时序序列并获取首次索引?

嘿,这个大规模时间序列的子序列匹配问题我之前处理过,刚好可以给你几个高效的解决方案——毕竟5万元素的A加上350元素的B,普通逐元素比对肯定慢到离谱:

高效解决方案:大规模Pandas序列子序列匹配

核心需求是:检测Series B是否作为连续有序子序列存在于Series A中,若存在则返回True和首次出现的起始索引,否则返回False和None。

方案一:Numpy滑动窗口视图(最快首选)

这个方法利用Numpy底层的内存视图操作,完全避免了Python层面的循环,速度拉满。原理是把Series转化为数组后,创建滑动窗口视图,直接用向量化操作比对每个窗口和B是否完全一致。

import pandas as pd
import numpy as np

def find_subsequence(series_a, series_b):
    arr_a = series_a.values
    arr_b = series_b.values
    len_a, len_b = len(arr_a), len(arr_b)
    
    # 如果B比A长,直接返回不存在
    if len_b > len_a:
        return False, None
    
    # 创建A的滑动窗口视图,形状为 (len_a - len_b + 1, len_b)
    # 注:Pandas Series的values默认是连续内存,所以这个方法可行
    window_view = np.lib.stride_tricks.sliding_window_view(arr_a, window_shape=len_b)
    
    # 逐行比对窗口和B是否完全匹配
    matches = np.all(window_view == arr_b, axis=1)
    match_indices = np.where(matches)[0]
    
    if match_indices.size > 0:
        return True, match_indices[0]
    return False, None

# 测试示例
series_a = pd.Series([1,2,3,4,5,6,5,4,3])
series_b = pd.Series([3,4,5])
print(find_subsequence(series_a, series_b))  # 输出: (True, 2)

适配NaN值的情况

如果序列中存在NaN,因为NaN != NaN,需要修改比对逻辑:

# 替换原matches行
matches = np.all(
    (window_view == arr_b) | (np.isnan(window_view) & np.isnan(arr_b)),
    axis=1
)

方案二:Rolling窗口+哈希校验(内存友好)

如果你的内存比较紧张,或者担心滑动窗口视图占用过多内存,可以用这个方法:先计算B的哈希值,再对A的滑动窗口计算哈希,通过哈希快速筛选候选,最后再校验避免哈希碰撞。

import pandas as pd
import numpy as np

def find_subsequence_hash(series_a, series_b):
    len_a, len_b = len(series_a), len(series_b)
    
    if len_b > len_a:
        return False, None
    
    # 计算B的哈希值(用tuple哈希足够快,也可以用更稳定的哈希算法)
    b_hash = hash(tuple(series_b.values))
    
    # 对A生成滑动窗口的哈希序列
    rolling_hashes = series_a.rolling(window=len_b).apply(
        lambda x: hash(tuple(x)),
        raw=True  # raw=True提升效率,直接传入numpy数组
    )
    
    # 找到所有哈希匹配的候选索引
    match_candidates = np.where(rolling_hashes == b_hash)[0]
    
    if not match_candidates.size:
        return False, None
    
    # 逐个校验候选窗口,避免哈希碰撞
    for idx in match_candidates:
        start_idx = idx - len_b + 1
        if np.array_equal(
            series_a.iloc[start_idx:start_idx+len_b].values,
            series_b.values
        ):
            return True, start_idx
    
    return False, None

# 测试示例
series_a = pd.Series([1,2,3,4,5,6,5,4,3])
series_b = pd.Series([3,4,5])
print(find_subsequence_hash(series_a, series_b))  # 输出: (True, 2)

关键注意事项

  • 两个Series的索引不会影响匹配逻辑,我们只比对值的顺序,所以用.values转化为数组是安全的。
  • 时间序列的话,确保你是要匹配值的顺序而非时间戳的顺序(如果时间戳是乱序的,需要先对Series A按时间戳排序)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 21:32:39