如何使这个matplotlib图更干净?

5 投票
2 回答
6158 浏览
提问于 2025-04-18 01:42

我想知道怎么把这些有噪音的数据画成一条平滑的连续线,而不去考虑每一个具体的数值。我只想展示数据的整体趋势,让它看起来更好,不用在意那些噪音和极端值。这是我正在使用的代码:

import numpy
import sys
import matplotlib.pyplot as plt
from scipy.interpolate import spline

dataset = numpy.genfromtxt(fname='data', delimiter=",") 

dic = {}

for d in dataset:
    dic[d[0]] = d[1] 

plt.plot(range(len(dic)), dic.values(),linestyle='-', linewidth=2)

plt.savefig('plot.png')
plt.show()

plot

2 个回答

0

有很多方法可以做到这一点!

在这里,我将展示如何使用各种技术来减少噪声:

  1. 移动平均
  2. LOWESS回归
  3. 低通滤波器
  4. 插值

为了保持一致,我将使用@Hooked的示例数据:

import numpy as np
import matplotlib.pyplot as plt

X = np.arange(1, 1000, 1)
Y = np.log(X ** 3) + 10 * np.random.random(X.shape)

plt.plot(X, Y, alpha = .5)
plt.show()

在这里输入图片描述


  1. 移动平均

有时候,你只需要一个移动平均

例如,使用pandas,窗口大小设置为100:

import pandas as pd

df = pd.DataFrame(Y, X)
df_mva = df.rolling(100).mean()  # moving average with a window size of 100

df_mva.plot(legend = False);

在这里输入图片描述

你可能需要尝试不同的窗口大小来适应你的数据。注意,df_mva的前100个值会是NaN,但可以通过dropna方法去掉这些值。

有关pandas滚动函数的使用细节。


  1. LOWESS回归

我曾成功使用LOWESS(局部加权散点平滑)来去除重复测量数据集中的噪声。关于局部回归方法的信息,包括LOWESS和LOESS,可以在这里找到。这是一种简单的方法,只需调整一个参数,根据我的经验,效果很好。

以下是如何使用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])  # some noise removed
plt.show()

在这里输入图片描述

可能需要调整frac参数,这个参数是用来估计每个y值时使用的数据比例。增大frac值可以增加平滑程度。frac的值必须在0到1之间。

有关statsmodels lowess使用的更多细节。


  1. 低通滤波器

Scipy提供了一系列低通滤波器,可能适合你的需求。

应用滤波器后:

from scipy.signal import lfilter

n = 50             # larger n gives smoother curves
b = [1.0 / n] * n  # numerator coefficients
a = 1              # denominator coefficient
y_lf = lfilter(b, a, Y)

plt.plot(X, y_lf)
plt.show()

在这里输入图片描述

查看scipy lfilter文档,了解关于如何在差分方程中使用分子和分母系数的实现细节。

scipy.signal包中还有其他滤波器。


  1. 插值

最后,这里是一个径向基函数插值的示例:

from scipy.interpolate import Rbf

rbf = Rbf(X, Y, function = 'multiquadric', smooth = 500)
y_rbf = rbf(X)

plt.plot(X, y_rbf)
plt.show()

在这里输入图片描述

通过增加smooth参数,可以实现更平滑的近似。可以考虑的其他function参数包括'cubic'和'thin_plate'。在选择function值时,我通常先尝试'thin_plate',然后是'cubic';不过在这个数据集中,'thin_plate'和'cubic'似乎都对噪声处理得不太好。

查看scipy文档中的其他Rbf选项。Scipy还提供其他单变量和多变量插值技术(请参见这个教程)。

8

在之前的一个回答中,我了解到了一种叫做Savitzky Golay滤波器的东西。这是一种特别的低通滤波器,非常适合用来平滑数据。你想要的曲线有多“平滑”其实是个人喜好的问题,这可以通过调整窗口大小和插值多项式的阶数来实现。下面是使用sg_filter的食谱示例:

import numpy as np
import sg_filter
import matplotlib.pyplot as plt


# Generate some sample data similar to your post
X = np.arange(1,1000,1)
Y = np.log(X**3) + 10*np.random.random(X.shape)

Y2 = sg_filter.savitzky_golay(Y, 101, 3)

plt.plot(X,Y,linestyle='-', linewidth=2,alpha=.5)
plt.plot(X,Y2,color='r')

plt.show()

enter image description here

撰写回答