繁体   English   中英

三次样条曲线拟合

[英]Curve fitting with cubic spline

我试图插入一个累积分布,例如 i) 人数到 ii) 拥有汽车的数量,这表明例如前 20% 的人拥有超过 20% 的汽车 - 当然 100% 的人拥有 100 辆汽车的百分比。 我也知道有例如 1 亿人和 2 亿辆汽车。

现在来看我的代码:

#import libraries (more than required here)
import pandas as pd
from scipy import interpolate
from scipy.interpolate import interp1d
from sympy import symbols, solve, Eq
import matplotlib.pyplot as plt
from matplotlib import pyplot as plt
%matplotlib inline
import plotly.express as px
from scipy import interpolate

curve=pd.read_excel('inputs.xlsx',sheet_name='inputdata')

输入数据:曲线图(左边累积的人(x)//右边累积的汽车(y))

#Input data in list form (I am not sure how to interpolate from a list for the moment)
cumulatedpeople = [0, 0.453086, 0.772334, 0.950475, 0.978981, 0.999876, 0.999990, 1]
cumulatedcars= [0, 0.016356, 0.126713, 0.410482, 0.554976, 0.950073, 0.984913, 1]

x, y = points[:,0], points[:,1]
interpolation = interp1d(x, y, kind = 'cubic')

number_of_people_mn= 100000000

oneperson = 1 / number_of_people_mn
dataset = pd.DataFrame(range(number_of_people_mn + 1))
dataset.columns = ["nr_of_one_person"]
dataset.drop(dataset.index[:1], inplace=True)

#calculating the position of every single person on the cumulated x-axis (between 0 and 1)
dataset["cumulatedpeople"] = dataset["nr_of_one_person"] / number_of_people_mn

#finding the "cumulatedcars" to the "cumulatedpeople" via interpolation (between 0 and 1)
dataset["cumulatedcars"] = interpolation(dataset["cumulatedpeople"])

plt.plot(dataset["cumulatedpeople"], dataset["cumulatedcars"])
plt.legend(['Cubic interpolation'], loc = 'best')
plt.xlabel('Cumulated people')
plt.ylabel('Cumulated cars')
plt.title("People-to-car cumulated curve")
plt.show()

然而,当查看实际的 plot 时,我得到以下错误结果:三次插值

事实上,该曲线应该看起来几乎像具有完全相同输入数据的线性插值的曲线 - 但这对于我的目的来说不够准确: Linear interpolation

是否有任何我遗漏的相关步骤,或者从几乎看起来像线性插值的输入中获得准确插值的最佳方法是什么?

简短回答:您的代码做的是正确的,但数据不适合三次插值。

让我解释。 这是您的代码,为了清楚起见,我简化了它

from scipy.interpolate import interp1d
from matplotlib import pyplot as plt

cumulatedpeople = [0, 0.453086, 0.772334, 0.950475, 0.978981, 0.999876, 0.999990, 1]
cumulatedcars= [0, 0.016356, 0.126713, 0.410482, 0.554976, 0.950073, 0.984913, 1]
interpolation = interp1d(cumulatedpeople, cumulatedcars, kind = 'cubic')

number_of_people_mn= 100#000000
cumppl = np.arange(number_of_people_mn + 1)/number_of_people_mn
cumcars = interpolation(cumppl)
plt.plot(cumppl, cumcars)
plt.plot(cumulatedpeople, cumulatedcars,'o')
plt.show()

请注意最后几行——我在同一张图上绘制了内插结果和输入日期。 这是结果样条1

橙色点是原始数据,蓝线是三次插值。 插值器通过所有的点,所以技术上是做正确的事

显然它没有做你想做的事

这种奇怪行为的原因主要是在右端,您有几个非常靠近的 x 点——插值器会产生巨大的摆动,试图适应非常靠近的点。

如果我从插值器中删除最右边的两个点:

interpolation = interp1d(cumulatedpeople[:-2], cumulatedcars[:-2], kind = 'cubic')

它看起来更合理一些: 样条2

但仍然有人会认为线性插值更好。 现在左端的摆动是因为初始 x 点之间的差距太大

这里的寓意是只有在 x 点之间的间隙大致相同时才真正使用三次插值

我认为你最好的选择是使用类似curve_fit的东西

可以在此处找到相关讨论

如此处所述,特别是单调插值会对您数据产生良好的结果。 在此处复制相关位,您可以将插值器替换为

from scipy.interpolate import pchip
interpolation = pchip(cumulatedpeople, cumulatedcars)

并获得体面的身材: 单调的

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM