使用matplotlib“平滑”点很少的直线

2024-06-16 11:45:28 发布

您现在位置:Python中文网/ 问答频道 /正文

这让我措手不及,似乎没有默认的支持来做类似的事情,甚至没有任何直接的方式

这种操作通常只需在Excel之类的程序中单击按钮即可

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

x = [1, 2, 3, 4]
y = [random.randint(0,10) for _ in range(4)]

plt.plot(x,y)
plt.show()

img

基本上,对于上面只有4个点的图,我想知道最简单的方法是简单地平滑直线,使其类似于曲线

更新: 因此,使用三次样条曲线通常可以做得很好

img

但有一个问题。在曲线中,我们可以看到,根据曲线的构建方式,存在高于实际观察到的最大点的点,以及低于实际最小点的点。是否有解决办法使曲线不超过最大观测点和最小观测点


Tags: import程序numpymatplotlibasnp方式plt
2条回答

您可以使用LOESSNadarya-Watson estimator(和变体)从离散数据获得平滑曲线。这些方法执行“移动平均”技术,因此它们通常不会产生原始数据范围以外的点(对于原始数据域内的x值)

有一个convenient python library(完整的免责声明,我是该库的作者)使此类模型易于构建。注意,结果通常不会通过给定的数据点

当带宽参数变为0时,曲线将成为线性插值。当它变为无穷大时,曲线将变成一条普通的最小二乘回归线。这两个值之间的带宽在这两个极端之间产生连续的曲线序列

import random
import numpy as np
import matplotlib.pyplot as plt
import sklearn.linear_model
import local_models.local_models as pylomo

np.random.seed(1)
x = [1, 2, 3, 4]
y = [random.randint(0,10) for _ in range(4)]
x_test = np.linspace(min(x), max(x), 100)

kernel = pylomo.GaussianKernel(bandwidth=0.5)
LOESS = pylomo.LocalModels(sklearn.linear_model.LinearRegression(), kernel=kernel)
LOESS.fit(np.array(x).reshape(-1,1), np.array(y))
y_pred = LOESS.predict(x_test.reshape(-1,1))

plt.plot(x,y)
plt.plot(x_test, y_pred, c='r')
plt.show()

enter image description here

一个简单的解决方案是使用scipy的interp1d通过点创建三次样条曲线

一种避免曲线超出周围点范围的方法是创建一条三次Bézier曲线,并在两个点之间添加额外的点

另一种方法涉及scipy的单调三次插值,^{},也称为pchip。此函数保持插值数据的单调性,如果数据不平滑,则不会超调

import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches
from scipy.interpolate import interp1d, pchip

x = np.array([1, 3, 4, 5, 6])
y = np.array([1, 6, 2, 5, 9])

plt.plot(x, y, 'ob:', lw=1)

x_smooth = np.linspace(x[0], x[-1], 500)
f1 = interp1d(x, y, kind='cubic')

plt.plot(x_smooth, f1(x_smooth), 'g')

f2 = pchip(x, y)
plt.plot(x_smooth, f2(x_smooth), 'r', lw=2)

x3 = np.convolve(np.repeat(x, 3), [1/3, 1/3, 1/3])[2:-2]
y3 = np.repeat(y, 3)[1:-1]
f3 = interp1d(x3, y3, kind='cubic')

plt.plot(x3, y3, 'k ', lw=0.5)

verts = list(zip(x3, y3))
codes = [Path.MOVETO] + [Path.CURVE4 for _ in range(len(verts) - 1)]
patch = patches.PathPatch(Path(verts, codes), facecolor='none', lw=3, edgecolor='m')
plt.gca().add_patch(patch)

plt.legend(['Linear', 'Cubic Spline', 'pchip', 'extra points', 'adapted Bezier'], handleheight=0.1)

plt.show()

resulting plot

请注意,还有多种其他类型的spline functions可用

相关问题 更多 >