异常值检测-滑动均值实现智能告警
来源:互联网 发布:imp命令导入远程数据库 编辑:程序博客网 时间:2024/06/07 16:07
前言
当前的分析对象是一段 timestamp-value 的时间序列,该时间序列可能是cpu使用率、磁盘使用率等数据。对于这些序列实现智能告警功能(也就是检测出一段序列中的异常值),因此需要我们在计算前,首先要定义什么样的值是异常值。
基于移动平均的方法,其朴素思想是在直观上来看图形,认为相近一段时间内的数据值,有相似的走向趋势。因此判断一个值是否是异常值,可通过判断该值是否对数据趋势造成了破坏,以此来得出结论。
如下图所示,其中某一点明显波动异常。所以直观上来看,就可以判断出该点是异常点。
那么如何通过某些方法,对异常点进行更加科学地判断以及代码实现。即本文主要工作内容。
移动平均方法介绍
简单移动平均
简单移动平均线(Simple Moving Average,SMA),是某变量之前 n 个数值的未作加权的算术平均。若计算收盘价的10日 SMA,是指“之前10日”收市价的平均值。假设,收市价为 p=(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10),则 SMA 公式为:
推广到一般情况为:
加权移动平均
加权移动平均(Weighted Moving Average,WMA),是指计算平均值时将各个数据分别乘以不同权重,其基本思想是赋予近期数据更高的行为权重。WMA是线性的。
若计算n日WMA,假设收市价为 p= (p1, p2, … , pn, pn+1, … , pm, …),则为若干天的收市价及依倒数顺序递减一的不同比例,来加权计算的移动平均线,公式如下:
指数加权移动平均
指数加权移动平均(EWMA:exponentially weighted moving average),公式如下:
x是实际值,s是ewma计算出来的平均值。也就是下一点的平均值是由上一点的平均值,加上当前点的实际值修正而来。这个修正的比例,就取决月这个alpha的decay factor的大小。视觉上来说就是ewma曲线是否紧跟实际曲线,也就是平滑程度。
要避免由于简单移动平均导致的缺陷,最简单的方法是对近期的数据赋予更高的权重。这也是指数加权移动平均法(EWMA)背后的基本思想
Python 实现
python pandas包中,对于ewma和sma有现成的实现方法。但是对于wma没有找到实现,在此,自己写了个简单地wma实现函数。
# coding:utf-8from __future__ import divisionimport pandas as pdimport matplotlib.pyplot as pltclass WMA(object): """ 加权移动平均实现 """ @staticmethod def get_wma_weights(span, flag=True): """ 计算每个数值点的wma权重值 """ paras = range(1, span + 1) count = sum(paras) if flag: return [float(para) / count for para in paras] else: return [float(para) / count for para in paras][::-1] def get_wma_values(self, datas): """ 计算wma数值 """ wma_values = [] wma_keys = datas.index for length in range(1, len(datas) + 1): wma_value = 0 weights = self.get_wma_weights(length) for index, weight in zip(datas.index, weights): wma_value += datas[index] * weight wma_values.append(wma_value) return pd.Series(wma_values, wma_keys)'''1. 首先构造测试数据'''# TODO 以后改成读取数据,直接生成 pandas Series 对象data_dict_series = { '1490707920': 19.8219660272, '1490707980': 20.0681534509, '1490708040': 20.1842385903, '1490708100': 19.7650368611, '1490708160': 19.9269200861, '1490708220': 18.470530654, '1490708280': 18.2211077462, '1490708340': 19.3140179366, '1490708400': 20.5632611228, '1490708460': 20.6341463476, '1490708520 ': 8.9789650937, '1490708580': 19.3494873891, '1490708640': 20.0160623292, '1490708700': 19.6702364186, '1490708760': 19.624609674, '1490708820': 20.456564799, '1490708880': 17.6035744548, '1490708940': 17.1818237007, '1490709000': 20.600406309, '1490709060': 19.9717502842, '1490709120': 20.0490164061, '1490709180': 20.1280070096, '1490709240': 20.579920421, '1490709300': 19.0682847972, '1490709360': 20.6150588592, '1490709420': 19.8059894244, '1490709480': 19.7459333887, '1490709540': 20.1206678947, '1490709600': 21.0094336718, '1490709660': 19.8375952393}dps = pd.Series(data_dict_series)'''2. ewma进行拟合'''ewma_line = pd.ewma(dps, span=4)'''3. 简单移动平均'''sma_line = pd.rolling_mean(dps, window=4)'''4. wma加权移动平均'''wma_line = WMA().get_wma_values(dps)'''5. 对原始数据和拟合结果数据进行画图'''# plt.figure(figsize=(10, 4))dps.plot(label='sample data')ewma_line.plot(label='sample data EMA result')sma_line.plot(label='sample data SMA result')wma_line.plot(label='sample data EWMA result')plt.legend()plt.show()
结果展示
SMA和原始数据对比
WMA和原始数据对比
EWMA和原始数据对比
总体平滑效果对比
异常点检测
上面通过滑动平均算法,得到了滑动均值,通过均值可计算方差,方差乘以一定的倍数可以得出对于振幅的容忍范围。比较实际的值是否超出了这个范围就可以知道是否可以告警了。
在本文的示例中,告警的正常的浮动范围设为一倍的方差。可以正常浮动范围可以根据实际业务进行调整。对于异常点监测通过如下代码实现。
# coding:utf-8from __future__ import divisionimport pandas as pdclass WMA(object): """ 加权移动平均实现 """ @staticmethod def get_wma_weights(span, flag=True): """ 计算每个数值点的wma权重值 """ paras = range(1, span + 1) count = sum(paras) if flag: return [float(para) / count for para in paras] else: return [float(para) / count for para in paras][::-1] def get_wma_values(self, datas): """ 计算wma数值 """ wma_values = [] wma_keys = datas.index for length in range(1, len(datas) + 1): wma_value = 0 weights = self.get_wma_weights(length) for index, weight in zip(datas.index, weights): wma_value += datas[index] * weight wma_values.append(wma_value) return pd.Series(wma_values, wma_keys)def calculate_variance(dps, moving_average): variance = 0 flag_list = moving_average.isnull() count = 0 for index in range(len(dps)): if flag_list[index]: count += 1 continue variance += (dps[index] - moving_average[index]) ** 2 variance /= (len(dps) - count) return variance'''1. 首先构造测试数据'''# TODO 以后改成读取数据,直接生成 pandas Series 对象data_dict_series = { '1490707920': 19.8219660272, '1490707980': 20.0681534509, '1490708040': 20.1842385903, '1490708100': 19.7650368611, '1490708160': 19.9269200861, '1490708220': 18.470530654, '1490708280': 18.2211077462, '1490708340': 19.3140179366, '1490708400': 20.5632611228, '1490708460': 20.6341463476, '1490708520 ': 8.9789650937, '1490708580': 19.3494873891, '1490708640': 20.0160623292, '1490708700': 19.6702364186, '1490708760': 19.624609674, '1490708820': 20.456564799, '1490708880': 17.6035744548, '1490708940': 17.1818237007, '1490709000': 20.600406309, '1490709060': 19.9717502842, '1490709120': 20.0490164061, '1490709180': 20.1280070096, '1490709240': 20.579920421, '1490709300': 19.0682847972, '1490709360': 20.6150588592, '1490709420': 19.8059894244, '1490709480': 19.7459333887, '1490709540': 20.1206678947, '1490709600': 21.0094336718, '1490709660': 19.8375952393}dps = pd.Series(data_dict_series)'''2. ewma进行拟合'''ewma_line = pd.ewma(dps, span=4)'''3. 简单移动平均'''sma_line = pd.rolling_mean(dps, window=4)'''4. wma加权移动平均'''wma_line = WMA().get_wma_values(dps)'''5. 计算告警'''# 计算每种平滑下原始数据的标准差sma_var = calculate_variance(dps, sma_line)wma_var = calculate_variance(dps, wma_line)ewma_var = calculate_variance(dps, ewma_line)flag_list = sma_line.isnull()for index in sma_line.index: if not (sma_line[index] - sma_var <= dps[index] <= sma_line[index] + sma_var): if not flag_list[index]: print "异常点", dps[index]print "=================================="for index in wma_line.index: if not (wma_line[index] - wma_var <= dps[index] <= wma_line[index] + wma_var): print "异常点", dps[index]print "=================================="for index in ewma_line.index: if not (wma_line[index] - ewma_var <= dps[index] <= wma_line[index] + ewma_var): print "异常点", dps[index]
输出结果如下图所示:
小结和参考
小结
本文使用了各种平滑算法对数据进行处理,但是算法见性能和效果,并没有进行科学地度量。这部分工作准备日后进行的。不过目前就从图上来看EWMA效果感觉还是不错的~~over
参考
告警方式介绍:
https://segmentfault.com/a/1190000003021919
滑动平均介绍:
http://www.cnblogs.com/liuning8023/p/3548770.html
https://en.wikipedia.org/wiki/Exponential_smoothing
相关代码实现:
http://stackoverflow.com/questions/9621362/how-do-i-compute-a-weighted-moving-average-using-pandas
http://stackoverflow.com/questions/18517722/weighted-moving-average-in-python
pandas用户手册:
http://pandas.pydata.org/pandas-docs/version/0.17.0/api.html#standard-moving-window-functions
- 异常值检测-滑动均值实现智能告警
- 告警实现
- 滑动均值滤波的matlab实现和Java实现
- 5-Spark高级数据分析-第五章 基于K均值聚类的网络流量异常检测
- 使用GestureDetector实现手指左右滑动检测
- cocos2d滑动碰撞检测的实现
- Zabbix实现告警分级
- PinPoint实现邮件告警
- 异常值检测算法
- 异常值检测
- 异常值检测
- HCM硬性K均值聚类算法 C++实现 【字幕检测、车牌识别】
- C语言try catch 异常检测实现
- 使用snmp4j实现trap告警
- Zabbix实现微信告警
- R语言--异常值检测
- C++实现K均值
- 滑动移动均值滤波简单代码实例
- HDU2003 求绝对值
- 安卓7.0源码编译
- 7个高级技巧释放macos空间
- linux无界面下selenium安装及使用示例
- 深度学习 1. CNN的构建和解释--最简单的CNN构造(LeNet-5)# By deepLearnToolbox-master
- 异常值检测-滑动均值实现智能告警
- Python中用json.loads解码字符串出错:ValueError: No JSON object could be decoded
- java实现输入两棵二叉树A,B,判断B是不是A的子结构
- 如何开发SDK
- 蓝桥杯java第八届B组:纸牌三角形
- Acegi Security in one hour
- Delaunay 三角网生成
- 用ffmpeg命令行转压视频
- ftp中常用命令