根据您的最终用途,可能值得考虑使用 LOWESS(局部加权散点图平滑)来消除噪声。我已经成功地将它与重复测量数据集一起使用。
有关局部回归方法的更多信息,包括 LOWESS 和 LOESS,here。
使用来自@lyken-syu 的示例数据与其他答案保持一致:
import numpy as np
import matplotlib.pyplot as plt
mu, sigma = 0, 500
x = np.arange(1, 100, 0.1) # x axis
z = np.random.normal(mu, sigma, len(x)) # noise
y = x ** 2 + z # signal + noise
plt.plot(x, y, linewidth = 2, linestyle = "-", c = "b") # includes some noise
plt.show()
下面是如何使用statsmodels 实现来应用LOWESS 技术:
import statsmodels.api as sm
y_lowess = sm.nonparametric.lowess(y, x, frac = 0.3) # 30 % lowess smoothing
plt.plot(y_lowess[:, 0], y_lowess[:, 1], 'b') # some noise removed
plt.show()
可能需要更改frac 参数,这是估计每个y 值时使用的数据的一部分。增加frac 值以增加平滑量。 frac 值必须介于 0 和 1 之间。
关于statsmodels lowess usage的更多详情。
有时一个简单的rolling mean 可能就足够了。
例如,使用窗口大小为 30 的pandas:
import pandas as pd
df = pd.DataFrame(y, x)
df_mva = df.rolling(30).mean() # moving average with a window size of 30
df_mva.plot(legend = False);
您可能需要对数据尝试几种窗口大小。
请注意,df_mva 的前 30 个值将是 NaN,但可以使用 dropna 方法删除这些值。
pandas rolling function 的使用详情。
最后,插值可用于通过平滑降噪。
这是来自scipy 的radial basis function interpolation 示例:
from scipy.interpolate import Rbf
rbf = Rbf(x, y, function = 'quintic', smooth = 10)
xnew = np.linspace(x.min(), x.max(), num = 100, endpoint = True)
ynew = rbf(xnew)
plt.plot(xnew, ynew)
plt.show()
通过增加smooth 参数可以实现更平滑的近似。要考虑的替代function 参数包括“cubic”和“thin_plate”。在考虑function 值时,我通常先尝试“thin_plate”,然后再尝试“cubic”; 'thin_plate' 给出了很好的结果,但对于这个数据集需要一个非常高的 smooth 值,而 'cubic' 似乎很难应对噪音。
检查scipy docs 中的其他Rbf 选项。 Scipy 提供了其他单变量和多变量插值技术(参见tutorial)。
如果您的数据以固定间隔进行采样,LOWESS 和滚动平均方法都将提供更好的结果。
径向基函数插值对于这个数据集来说可能是多余的,但如果您的数据是更高维度的和/或不是在常规网格上采样的,那么它绝对值得您注意。
所有这些方法都必须小心;很容易去除过多的噪声并扭曲基础信号。