时间序列之拐点检测(changepoints detection)算法

一、前言

对于时间拐点问题,其实就是找changepoint的问题,业务场景比如机器的缩扩容,业务的升级回滚等,都会让一些指标发生这样的现象, 如下图。(这种场景比较理想,现实情况要复杂得多)

52110c62d69365919c9f36ceef6cd79f.jpeg

为了检测这个区域,需要使用changepoint detector:ruptures

二、ruptures

ruptures 是专门用于检测时间序列数据中的结构性变化,这种变化也常被称为断点(breakpoints)或变点(changepoints)。

库提供了多种算法来检测时间序列中的突变或者异常模式变化。这些算法能够识别出时间序列数据中的突变,这些突变可能表明了一些潜在的事件或状态变化。

项目地址:https://github.com/deepcharles/ruptures 官方文档在这里 http://ctruong.perso.math.cnrs.fr/ruptures

2.1 安装

pip install ruptures

2.2 使用

其中有很多算法供选择,这里选择Dynp(dynamic programming.)

其他算法使用可以参考:https://forecastegy.com/posts/change-point-detection-time-series-python/#detecting-change-points-with-binary-segmentation

import matplotlib.pyplot as plt
import ruptures as rpt
import numpy as np

mean = 0
std_dev = 1
length_of_series = 100
values = np.random.normal(mean, std_dev, length_of_series)

values[-35:] = values[-35:] + 10

# 找拐点
algo = rpt.Dynp(model="l2", min_size=3, jump=3).fit(values)
# 检测断点,指定最大断点数
result = algo.predict(n_bkps=1)
result = result[:-1]
# 显示结果
plt.plot(values)
for bkp in result:
    plt.axvline(x=bkp, color='r', linestyle='--')
plt.show()
0b00ffcded848bfcce7631fd88951c52.jpeg

参数:

  • model:用于计算cost的function,根据这个来找changepoint

  • custom_cost: 自定义cost function

  • min_size:最小的分段长度。

  • jump:在进行断点搜索时的采样步长。

2.3 源码简单解析

predict源码:

33d6c7f0281127cafa70addfc883409d.jpeg

实则还是self.seg是核心函数,结果通过长度的index进行排序 输出的结果格式为长度的index,看上面给出的results就明白了。

@lru_cache(maxsize=None)
    def seg(self, start, end, n_bkps):
        """Recurrence to find the optimal partition of signal[start:end].

        This method is to be memoized and then used.

        Args:
            start (int): start of the segment (inclusive)
            end (int): end of the segment (exclusive)
            n_bkps (int): number of breakpoints

        Returns:
            dict: {(start, end): cost value, ...}
        """
        jump, min_size = self.jump, self.min_size

        if n_bkps == 0:
            cost = self.cost.error(start, end)
            return {(start, end): cost}
        elif n_bkps > 0:
            # Let's fill the list of admissible last breakpoints
            multiple_of_jump = (k for k in range(start, end) if k % jump == 0)
            admissible_bkps = list()
            for bkp in multiple_of_jump:
                n_samples = bkp - start
                # first check if left subproblem is possible
                if sanity_check(
                    n_samples=n_samples,
                    n_bkps=n_bkps - 1,
                    jump=jump,
                    min_size=min_size,
                ):
                    # second check if the right subproblem has enough points
                    if end - bkp >= min_size:
                        admissible_bkps.append(bkp)

            assert (
                len(admissible_bkps) > 0
            ), "No admissible last breakpoints found.\
             start, end: ({},{}), n_bkps: {}.".format(
                start, end, n_bkps
            )

            # Compute the subproblems
            sub_problems = list()
            for bkp in admissible_bkps:
                left_partition = self.seg(start, bkp, n_bkps - 1)
                right_partition = self.seg(bkp, end, 0)
                tmp_partition = dict(left_partition)
                tmp_partition[(bkp, end)] = right_partition[(bkp, end)]
                sub_problems.append(tmp_partition)

            # Find the optimal partition
            return min(sub_problems, key=lambda d: sum(d.values()))

稍微看下 这个源码,大致就懂这个算法的含义了。

  1. 通过jump大小得到可能的候选边界

  2. 通过min_size的大小比较,得到每段的前后边界组合

  3. 进行递归

  4. 如果没有分块,则计算此时的时间序列段的cost value

  5. 得到所有分块的cost值,找到此时cost的最小值

这个其实比较暴力了,相当于目标函数cost fuction最小化。不暴力的有贝叶斯的方法:Bayesian Online Changepoint Detection

2.4 一些问题

  1. 这个必须要预先设置要检测多少个拐点

  2. 比如要大于min_size

这两个问题对于实际应用,基本不会知道检测的长度预先有多少个拐点,其次大于min_size这个要求如果是流式场景肯定会有一定的延迟。

所以对于流式场景这个只能检测过去几个点的拐点状态,无法实时检测出来。

并且针对第一个问题,不知道有多少个,那我们也可以通过卡阈值的方式来自动化的选出排名前部的边界

# 找拐点
algo = rpt.Dynp(model="l2", min_size=3, jump=3).fit(values)
# 这块n可以很多,但是要满足分割的条件, 直接采用 seg
partition = algo.seg(0, algo.n_samples, n_bkps=10)
# 输出的肯定有最后一个边界要去掉
filter_partition = {}
for key, value in partition.items():
    if key[1] == algo.n_samples:
        continue
    filter_partition[key] = value
partition = filter_partition
sort_partition = sorted(partition.items(), key=lambda x: x[1], reverse=True)

后续怎么操作就看需求了,可以按照cost大小进行排序,也可以直接根据数量取前面的等等

推荐阅读:

我的2022届互联网校招分享

我的2021总结

浅谈算法岗和开发岗的区别

互联网校招研发薪资汇总

公众号:AI蜗牛车

保持谦逊、保持自律、保持进步

64e9c9bb1b7e750a8c06ddc35a6eaaef.jpeg

发送【蜗牛】获取一份《手把手AI项目》(AI蜗牛车著)

发送【1222】获取一份不错的leetcode刷题笔记

发送【AI四大名著】获取四本经典AI电子书

  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在卫星时间序列数据中检测变点、趋势和季节性是一项重要的任务。卫星时间序列数据是通过卫星观测到的地球表面上的连续观测数据。这些数据可以用于监测和分析地球表面的变化,如气象、土地利用和植被覆盖等。 首先,检测变点是指在时间序列找到突变或结构转变的点。变点可能代表了不同的影响因素引起的突变,例如自然事件、人为活动或仪器故障等。通过分析时间序列数据的变化趋势,可以使用一些统计方法来检测这些变点。 其次,趋势是指时间序列数据中长期的变化方式。有时,卫星时间序列数据中的变化可能会逐渐增长或减少,这可以被称为趋势。通过对时间序列数据进行回归分析或移动平均处理,我们可以检测和评估这种趋势。 季节性是指在一年内周期性的重复出现的模式。例如,地表温度通常会因季节变化而发生变化,夏季温度高,冬季温度低。对于卫星时间序列数据,我们可以通过分析数据的周期性变化来检测季节性。一种常用的方法是使用季节分解技术,如STL分解,将时间序列分解成长期趋势、季节变化和随机噪声部分。 通过检测卫星时间序列数据中的变点、趋势和季节性,我们可以更好地理解地球表面的变化,并为环境监测和资源管理提供更准确的信息。这些分析结果可以用于研究气候变化、土地利用变化、植被变化等,以及评估其对环境和人类社会的影响。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值