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);
看看我们都做了什么:
我们首先取了整个数据集,点与点之间的差值;abs后,取平均 => diff_average;
然后,我们依次扫描这个区间,如果发现某个区间出现了异常数据点,我们就把前一个点,计入flow_pt数组,然后输出。
最终的输出参数中,我们给出了两个数据:有可能有问题的数据点,以及当前我们采集到的数据点的平均差值。
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;
受益的同志,别忘了留个言,这个问题困扰我好久,今天总算近乎一劳永逸地解决了。