You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中生成递增平滑样条曲线而非非均匀递增曲线

解决累积百分位数样条平滑的单调不减问题

我用样条平滑累积百分位数数据(x轴为参考点,y轴为累积百分位数),目前实现基本正确,但生成的样条曲线y值出现波动,并非单调递增。需要生成平滑且y随x单调不减的曲线。

可复现代码:

import pandas as pd 
import numpy as np 
from scipy.interpolate import make_interp_spline 
import matplotlib.pyplot as plt 
from matplotlib.pyplot import figure 

percentile_block_df = pd.DataFrame({ 
'x' : [0.5,100.5,200.5,400.5,800.5,900.5,1000.5], 
'percentile' : [0.0001,0.01,0.065,0.85,0.99,0.9973,0.9999] 
})

figure(figsize=(8, 6), dpi=80) 
y = percentile_block_df.percentile 
x = percentile_block_df.x 

X_Y_Spline = make_interp_spline(x, y) 

# 生成指定区间内的均匀分布点
X_ = np.linspace(x.min(), x.max(), 1000)
Y_ = X_Y_Spline(X_)

figure(figsize=(18, 6), dpi=80)
plt.subplot(1, 2, 1) # 第1行第2列第1个图
plt.plot(x, y,"ro")
plt.plot(x, y)
plt.title("Original")
plt.xlabel('X')
plt.ylabel('Percentile ')

plt.subplot(1, 2, 2) # 第1行第2列第2个图
plt.plot(x, y,"ro")
plt.plot(X_, Y_,"green")
plt.title("Spline Plot")
plt.xlabel('X')
plt.ylabel('Percentile ')

plt.show()

当前样条曲线效果:
当前样条曲线效果


解决方案

普通B样条(make_interp_spline默认生成)不保证单调性,而累积百分位数本身是单调不减的,因此需要使用单调插值方法:

方法1:PCHIP保形分段三次Hermite插值

scipy.interpolate.PchipInterpolator专门用于生成单调平滑曲线,严格保证插值结果与原数据的单调性一致。

修改后的代码:

import pandas as pd 
import numpy as np 
from scipy.interpolate import PchipInterpolator  # 替换为PCHIP插值
import matplotlib.pyplot as plt 
from matplotlib.pyplot import figure 

percentile_block_df = pd.DataFrame({ 
'x' : [0.5,100.5,200.5,400.5,800.5,900.5,1000.5], 
'percentile' : [0.0001,0.01,0.065,0.85,0.99,0.9973,0.9999] 
})

y = percentile_block_df.percentile 
x = percentile_block_df.x 

# 使用PCHIP替代普通样条
X_Y_Spline = PchipInterpolator(x, y) 

X_ = np.linspace(x.min(), x.max(), 1000)
Y_ = X_Y_Spline(X_)

figure(figsize=(18, 6), dpi=80)
plt.subplot(1, 2, 1)
plt.plot(x, y,"ro")
plt.plot(x, y)
plt.title("Original")
plt.xlabel('X')
plt.ylabel('Percentile ')

plt.subplot(1, 2, 2)
plt.plot(x, y,"ro")
plt.plot(X_, Y_,"green")
plt.title("Monotonic PCHIP Spline Plot")
plt.xlabel('X')
plt.ylabel('Percentile ')

plt.show()

方法2:单调B样条

若偏好使用B样条,可使用scipy.interpolate.make_monotone_spline(需SciPy 1.10及以上版本),它会生成满足单调性约束的B样条曲线:

示例代码片段:

from scipy.interpolate import make_monotone_spline

# 替换插值逻辑
X_Y_Spline = make_monotone_spline(x, y)
X_ = np.linspace(x.min(), x.max(), 1000)
Y_ = X_Y_Spline(X_)

效果说明

  • PCHIP插值生成的曲线完全保持单调不减,同时贴合原数据趋势,平滑度满足需求。
  • 单调B样条同样保证单调性,曲线平滑度可能略高于PCHIP,适配不同场景需求。

内容的提问来源于stack exchange,提问作者user3562074

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 04:55:16