用neighbour-Value替换离群值

时间:2018-10-09 14:22:46

标签: python pandas numpy matplotlib

我有一个带有一些异常值(错误的测量值)的图:

enter image description here

虽然基本数据很好。我只想删除与“当前平均值”相差太远的所有内容。我尝试使用pd.rolling().mean(),但没有令人满意的结果:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

data = np.genfromtxt('shard_height_plot.csv', delimiter = ',')
df = pd.DataFrame(data)
df.set_index(0, inplace = True)
df2 = df.rolling(20).mean()

plt.plot(df)
plt.plot(df2)
plt.show()

enter image description here

我试图在网络上搜索一个好的解决方案,但找不到。删除数据点不应该那么困难,应该跳过吗?

编辑: 数据文件可在此处下载:https://ufile.io/pviuc

Edit2:

我通过改善数据集的创建解决了太多异常值的问题。

它的核心:

if abs(D - D_List[-2]) > 30:
            D = D_List[-2]
            D_List.pop()
            D_List.append(D)

基本上,这是检查值的更改是否大于30,如果是,它将删除最后一个值,并用倒数第二个替换。不是很壮观,但正是我所需要的。我使用了答案之一,因为它太漂亮了。非常感谢你们。

enter image description here

2 个答案:

答案 0 :(得分:3)

让我们尝试使用scipy.signal see docs

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from scipy import signal

data = np.genfromtxt('shard_height_plot.csv', delimiter = ',')
df = pd.DataFrame(data)
df.set_index(0, inplace = True)
df2 = df.rolling(20).mean()

b, a = signal.butter(3, 0.05)
y = signal.filtfilt(b,a, df[1].values)

df3 = pd.DataFrame(y, index=df2.index)


plt.plot(df, alpha=.3)
plt.plot(df2, alpha=.3)
plt.plot(df3)
plt.show()

输出:

enter image description here

使用medfilt:

y = signal.medfilt(df[1].values)

输出:

enter image description here

答案 1 :(得分:1)

有许多种方法可以平滑曲线(滚动平均值,GAM,平滑样条曲线等),我最喜欢的方法是Savitzky–Golay方法。 它的工作方式如下:将围绕数据点y的小窗口回归到多项式(最小二乘)后,它使用该多项式来获取对数据点^y的估计。然后将窗口向前移动一个数据点。

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import savgol_filter

x = np.linspace(0,5,150)
y = np.cos(x) + np.random.random(150) * 0.15
yhat = savgol_filter(y, 49, 3)

plt.plot(x,y)
plt.plot(x,yhat, color='red')
plt.show()

enter image description here

请注意,在周长低至20的情况下,滚动平均值不适用于您的情况,因为异常点的权重(5%)不可忽略,并且总是会引起较大的偏倚...