python - 三次样条曲线拟合
问题描述
我试图插入一个累积分布,例如 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()
但是,在查看实际图时,我得到以下错误的结果:三次插值
事实上,曲线应该看起来几乎像来自具有完全相同输入数据的线性插值的曲线 - 但是这对于我的目的来说不够准确:线性插值
我是否遗漏了任何相关步骤,或者从几乎看起来像线性插值的输入中获得准确插值的最佳方法是什么?
解决方案
简短的回答:您的代码正在做正确的事情,但数据不适合三次插值。
让我解释。这是我为清楚起见简化的代码
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()
注意最后几行——我在同一张图上绘制了插值结果和输入日期。这是结果
橙色点是原始数据,蓝色线是三次插值。插值器通过所有点,因此从技术上讲是正确的
显然它没有做你想做的事
这种奇怪行为的原因主要是在右端,你有几个非常靠近的 x 点 - 插值器产生大量摆动,试图拟合非常接近的点。
如果我从插值器中删除两个最右边的点:
interpolation = interp1d(cumulatedpeople[:-2], cumulatedcars[:-2], kind = 'cubic')
但是仍然有人会认为线性插值更好。现在左端的摆动是因为初始 x 点之间的间隙太大
这里的寓意是,只有当 x 点之间的间隙大致相同时,才应该真正使用三次插值
我认为你最好的选择是使用类似curve_fit的东西
相关讨论可以在这里找到
特别是这里解释的单调插值对您的数据产生良好的结果。在此处复制相关位,您可以将插值器替换为
from scipy.interpolate import pchip
interpolation = pchip(cumulatedpeople, cumulatedcars)
推荐阅读
- vb.net - 以毫秒为单位的总数据。在 vb.net 上访问
- kubernetes - 我在哪里可以看到在 Kubernetes Discovery 中注册的服务列表?
- metasploit - 如何将已经打开的 shell 导入 metasploit
- php - 如何在 Laravel 中使用 Angular
- javascript - 如何根据单击的按钮更改代码
- c++ - 如何在 Win32 API 中将按钮控件的位置设置为正好在窗口的中间
- r - 遍历 url 列表并下载 html 表 R
- cordova - 在 Cordova iOS 应用程序上检测/禁用屏幕录制
- javascript - React JS:组件未导出
- javascript - 威迪奥,摩卡咖啡。如何创建(随机生成)全局变量并在每次测试中使用它