Использование matplotlib для сглаживания линии с очень небольшим количеством точек - PullRequest
0 голосов
/ 13 апреля 2020

Меня застигло врасплох, как будто нет поддержки по умолчанию для выполнения чего-то подобного, и даже нет прямого пути.

Этот тип операции обычно так же прост, как нажатие кнопки в программе, такой как 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 точки, мне интересно, какой наименее сложный способ состоит в том, чтобы просто сгладить линию, чтобы она вместо этого напоминала кривую ,

Обновление: так что использование сплайна cubi c в основном делает большую работу!:

img

Одна проблема, однако. На кривой мы видим, что в зависимости от того, как построена кривая, есть точки выше, чем фактическая максимальная наблюдаемая точка, и точки ниже, чем фактический минимум. Есть ли обходной путь, чтобы сделать так, чтобы кривая не превышала максимально наблюдаемые и минимальные точки?

Ответы [ 2 ]

2 голосов
/ 13 апреля 2020

Вы можете использовать LOESS или Оценку Надаря-Ватсона (и варианты) для получения гладкой кривой из дискретных данных. Эти методы выполняют технику «скользящего среднего», так что они обычно не дают точек вне диапазона исходных данных (для значений x, которые находятся в области исходных данных) .

Существует удобная python библиотека (полный отказ от ответственности, я автор библиотеки), которая позволяет легко создавать такие модели. Позаботьтесь о том, чтобы результат, как правило, не проходил через заданные точки данных.

При изменении значения параметра полосы пропускания до 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

2 голосов
/ 13 апреля 2020

Простое решение использует scipy's interp1d для создания сплайна куби c через точки.

Подход, позволяющий избежать выхода кривой за пределы диапазона окружающих точек, состоит в следующем: чтобы создать кубическую c кривую Безье с добавлением дополнительных промежуточных точек:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches
from scipy.interpolate import interp1d

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

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')

x2 = np.convolve(np.repeat(x, 3), [1/3,1/3,1/3])[2:-2]
y2 = np.repeat(y, 3)[1:-1]
f2 = interp1d(x2, y2, kind='cubic')

plt.plot(x2, y2, 'k--', lw=0.5)

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

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

plt.show()

resulting plot

Обратите внимание, что также несколько других типов доступны сплайн-функции .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...