一种自适应异常数据点消除方法

1.问题

在现实生活中,采集到的信号,会有一些噪点需要去除,否则这部分数据在比如时域空间直接进行分析时就会遇到非常难以厘清的逻辑要处理,各种异常。 肉眼看去,那些噪点是清清楚楚的。如何去除呢?

这里给出我的这种异常数据点的筛除算法最终的执行效果(滤除异常数据点后的数据参见点状图中红色的smooth之后的曲线),可以看到,它的效果是很好的。数据的原始波形参见下方绿色连线图。

2.处理逻辑

2.1.析取错误数据点

#析取所有的异常数据点
def output_flaw_data_byLOF(data, ratio = 5):
    x = np.arange(1,len(data));
    diff_ar = [];
    sum  = 0;
    for i in x:
        dumb = abs(data[i] - data[i-1]);
        diff_ar.append(dumb);
        sum = sum + dumb;
    diff_average = sum/(len(data)-1)

    flaw_pt = [];
    sum2 = 0;
    for i in x:
        dumb = abs(data[i] - data[i-1]);
        if(dumb >= ratio*diff_average):
            flaw_pt.append(i-1);
        else:
            sum2 = sum2 + dumb;
    diff_average_remove_flaws = sum2/(len(data)-len(flaw_pt)-1);
    return (flaw_pt, diff_average, diff_average_remove_flaws);

看看我们都做了什么:

  1. 我们首先取了整个数据集,点与点之间的差值;abs后,取平均 => diff_average;
  2. 然后,我们依次扫描这个区间,如果发现某个区间的差值超过了平均数据点的适当比例——出现了异常数据点,我们就把这个区间的前一个点,计入flow_pt数组,然后输出。
  3. 最终的输出参数中,我们给出了三个数据:
    1. 有可能有问题的数据点,
    2. 当前我们采集到的数据点的平均差值。
    3. 去除异常数据点后的正常数据点的平均差值。

最后的两个参数可以供调用者决策,是否需要调整参数,进一步做平均处理。

2.2.抹掉错误数据点

抹掉数据点后,还需要补回,也就是插值。需要根据前后数据点的趋势来尝试逆推,用插值法插出缺失的数据点,插值简单起见,使用了线性差值法:

#针对异常数据点,逐一抹平
def smooth_sample_data_byLOF(data_origin, ratio = 5):
    data = data_origin.copy();
    cnts = 5;
    while(True):
        (flaw_pt, diff_average, diff_average_remove_flaws) = output_flaw_data_byLOF(data, ratio);
        if(abs(diff_average_remove_flaws - diff_average)/diff_average)<1: break;
        else:
            cnts = cnts -1;
            if(cnts <=0):
                break;
            else:
                continue;
    dealed = [];
    for x in flaw_pt:
        if(x in dealed): continue;
        else:
            ref_pts_prev = [];
            i = x;
            while(i>0):
                i = i-1;
                if(not(i in flaw_pt)):
                    ref_pts_prev.append(i);
                    if(len(ref_pts_prev)>=2):
                        break;
                    else:
                        continue;
                else:
                    continue;
            ref_pts_post = [];
            i = x;
            while(i<len(data)):
                i = i+1;
                if(not(i in flaw_pt)):
                    ref_pts_post.append(i);
                    if(len(ref_pts_post)>=2):
                        break;
                    else:
                        continue;
                else:
                    continue;
            
            if(len(ref_pts_prev)!=0) and (len(ref_pts_post)!=0):
                dx = (ref_pts_post[0] - ref_pts_prev[0]);
                dy = data[ref_pts_post[0]] - data[ref_pts_prev[0]];
                ref_y = data[ref_pts_post[0]];
                ref_x = x - ref_pts_post[0];
                data[x] = ref_y + dy/dx*ref_x;
            else:
                if(len(ref_pts_prev)==0):
                    dx = (ref_pts_post[1] - ref_pts_post[0]);
                    dy = data[ref_pts_post[1]] - data[ref_pts_post[0]];
                    ref_y = data[ref_pts_post[0]];
                    ref_x = x - ref_pts_post[0];
                    data[x] = ref_y + dy/dx*ref_x;
                else:
                    dx = (ref_pts_prev[1] - ref_pts_prev[0]);
                    dy = data[ref_pts_pre[1]] - data[ref_pts_prev[0]];
                    ref_y = data[ref_pts_prev[0]];
                    ref_x = x - ref_pts_prev[0];
                    data[x] = ref_y + dy/dx*ref_x;
    return data;

受益的同志,别忘了留个言,这个问题困扰我好久,今天总算近乎一劳永逸地解决了。可以看到,示例的波形里有一个异常数据点没有校回,你知道原因在哪里,该怎么做吗?

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

子正

thanks, bro...

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值