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

如何生成通过数据点的平滑曲线?当前插值曲线存在不平滑问题

如何优化得到穿过数据点的平滑曲线?

你尝试生成穿过数据点的平滑曲线,但结果要么是直线连接散点,要么点间区域出现异常凸起。当前实现代码如下:

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import matplotlib.pyplot as plt
from matplotlib.ticker import (MultipleLocator, AutoMinorLocator)
from numpy.polynomial.polynomial import Polynomial
from scipy.interpolate import BSpline
from scipy.interpolate import interp1d
Time=[0.1,0.5,1,5,10,50,100,250,500,1000,2500,5000]
Intensity=[2722.164194,2877.627742,2663.520645,2708.928125,2545.461613,2421.236129,1885.837742,1710.483871,1275.428387,776.0895806,192.4806452,26.35279]
fun = interp1d(x=Time, y=Intensity, kind=2,bounds_error=False)
x2 = np.linspace(start=-0.1, stop=5000, num=100000)
y2 = fun(x2)
fig, ax = plt.subplots()
ax.scatter(Time, Intensity)
ax.plot(x2,y2, color="r")
ax.xaxis.set_major_locator(MultipleLocator(500))
ax.xaxis.set_minor_locator(MultipleLocator(100))
ax.yaxis.set_major_locator(MultipleLocator(500))
ax.yaxis.set_minor_locator(MultipleLocator(100))
ax.set_xlabel("Trapping time (ms)")
ax.set_ylabel("Average Intensity (counts/s)")

生成的曲线图像:
曲线图像


问题根源

你当前使用的interp1d(kind=2)是二次样条插值,但时间数据是对数分布(前几个点极密集,后面跨度极大),这种不均匀采样会让二次样条在稀疏区域出现震荡凸起;另外bounds_error=False会让超出原始x范围的部分返回nan,导致曲线开头断裂。

优化方案

1. 对数轴适配插值(最贴合数据分布)

因为时间是指数增长的,先对x取对数后再插值,让采样更均匀,避免震荡:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import (MultipleLocator, AutoMinorLocator)
from scipy.interpolate import interp1d

Time = [0.1,0.5,1,5,10,50,100,250,500,1000,2500,5000]
Intensity = [2722.164194,2877.627742,2663.520645,2708.928125,2545.461613,2421.236129,1885.837742,1710.483871,1275.428387,776.0895806,192.4806452,26.35279]

# 对时间取自然对数,将不均匀采样转为均匀
log_time = np.log(Time)
# 用三次样条插值,指定fill_value='extrapolate'处理边界外的点
fun = interp1d(x=log_time, y=Intensity, kind='cubic', fill_value='extrapolate')

# 生成对数均匀的插值点,再转回原始时间尺度
log_x2 = np.linspace(np.log(0.1), np.log(5000), num=1000)
x2 = np.exp(log_x2)
y2 = fun(log_x2)

fig, ax = plt.subplots()
ax.scatter(Time, Intensity)
ax.plot(x2, y2, color="r")
# 可选:将x轴设为对数刻度,更匹配数据趋势
ax.set_xscale('log')
ax.xaxis.set_major_locator(MultipleLocator(500))
ax.xaxis.set_minor_locator(MultipleLocator(100))
ax.yaxis.set_major_locator(MultipleLocator(500))
ax.yaxis.set_minor_locator(MultipleLocator(100))
ax.set_xlabel("Trapping time (ms)")
ax.set_ylabel("Average Intensity (counts/s)")
plt.show()

2. 手动B样条插值(保持原始坐标轴)

如果不想用对数轴,可以用make_interp_spline生成三次B样条,它会自动优化节点分布,减少震荡:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import (MultipleLocator, AutoMinorLocator)
from scipy.interpolate import make_interp_spline

Time = [0.1,0.5,1,5,10,50,100,250,500,1000,2500,5000]
Intensity = [2722.164194,2877.627742,2663.520645,2708.928125,2545.461613,2421.236129,1885.837742,1710.483871,1275.428387,776.0895806,192.4806452,26.35279]

# 生成三次B样条插值函数
spl = make_interp_spline(Time, Intensity, k=3)
# 在原始时间范围内生成密集插值点
x2 = np.linspace(min(Time), max(Time), num=1000)
y2 = spl(x2)

fig, ax = plt.subplots()
ax.scatter(Time, Intensity)
ax.plot(x2, y2, color="r")
ax.xaxis.set_major_locator(MultipleLocator(500))
ax.xaxis.set_minor_locator(MultipleLocator(100))
ax.yaxis.set_major_locator(MultipleLocator(500))
ax.yaxis.set_minor_locator(MultipleLocator(100))
ax.set_xlabel("Trapping time (ms)")
ax.set_ylabel("Average Intensity (counts/s)")
plt.show()

3. 边界处理优化

不要让插值范围超出原始数据的x区间(你之前从-0.1开始,这部分无数据支撑);如果必须外推,用fill_value='extrapolate'替代bounds_error=False,后者会返回nan导致曲线断裂。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 00:07:04