去除数据中的异常值,保持原始趋势

问题描述 投票:0回答:2

在我的图中,你可以看到只有一些噪音。我尝试使用 scipy.signal savgol_filter,但趋势已经改变。我只是想消除这些噪音并使它们符合曲线。谢谢你。

python data-cleaning curve-fitting outliers
2个回答
1
投票

我认为您将噪声与异常值混淆了,请参阅:噪声与异常值之间的基本差异。 您可以尝试通过许多不同的方法删除异常值,例如使用 z 分数:

df = df.mask(np.abs(stats.zscore(df)) < 2) # here we are setting limit on z-score on 2 - you can experiment with values best suited to your data

重要提示:您应该在从数据中删除趋势后执行此操作。


0
投票

让我们重新创建一个数据集:

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats, signal, optimize

np.random.seed(12345)

def model(x, a, b, c):
    return a*np.exp(-b*x) + c

x = np.linspace(0, 350, 200)
y = model(x, 100, 0.01, 75)
n = np.random.normal(size=x.size)
yn = y + n

yn[20] *= 0.75
yn[21] *= 0.5
yn[22] *= 1.75
yn[23] *= 0.25
yn[24] *= 0.20
yn[25] *= 0.75
yn[100] *= 0.5
yn[101] *= 1.75

如果异常值不是太强或太多,我们可以通过用异常值拟合曲线来估计趋势:

popt1, pcov1 = optimize.curve_fit(model, x, yn)
yhat1 = model(x, *popt1)

# (array([9.27557251e+01, 1.02647524e-02, 7.64660389e+01]),
#  array([[ 1.94284082e+01,  7.21272130e-04, -3.70396525e+00],
#         [ 7.21272130e-04,  1.80489353e-06,  3.75303063e-03],
#         [-3.70396525e+00,  3.75303063e-03,  1.05002199e+01]]))

这已经接近最佳参数,但受异常值支配(参见协方差)。

或者我们按照您的建议使用一些过滤器平滑曲线:

yhat1 = signal.savgol_filter(yn, 150, 3)

然后,正如 @Matmozaur 所建议的,z 分数是过滤异常值的一个很好的标准:

zs = stats.zscore(yhat1 - yn)
mask = np.abs(zs) <= 2

现在我们已经识别出异常值,我们可以在没有它们的情况下拟合函数:

popt2, pcov2 = optimize.curve_fit(model, x[mask], yn[mask])
yhat2 = model(x, *popt2)

# (array([9.90714297e+01, 1.01604158e-02, 7.54550734e+01]),
# array([[ 5.81279449e-01,  1.70129801e-05, -1.13880755e-01],
#        [ 1.70129801e-05,  4.43252922e-08,  1.00312909e-04],
#        [-1.13880755e-01,  1.00312909e-04,  3.04817515e-01]]))

对于这种设置来说,这是相当可以接受的。

© www.soinside.com 2019 - 2024. All rights reserved.