Python中无公式曲线的一阶导数计算绘制及导数半最大值点提取方法
离散点曲线求导及半最大值点提取Python实现
这个需求完全可以在Python中实现,以下是可直接运行的完整方案:
前置依赖
先安装需要用到的第三方库:
pip install pandas numpy scipy matplotlib
完整实现代码
import pandas as pd import numpy as np import matplotlib.pyplot as plt from scipy.interpolate import UnivariateSpline # 构造样本数据 data = [ [-0.000131, 0.006983], [0.013764, 0.006666], [0.028727, 0.007242], [0.137593, 0.007117], [0.538855, 0.007305], [0.963937, 0.008790], [1.318019, 0.011174], [1.569953, 0.012909], [1.751192, 0.016706], [1.957168, 0.020321], [2.125429, 0.028622], [2.297202, 0.035952], [2.483939, 0.046041], [2.663194, 0.056283], [2.855580, 0.068497], [3.043233, 0.082118], [3.243100, 0.097764], [3.437318, 0.111928], [3.639782, 0.129328], [3.839039, 0.145694], [4.044403, 0.163474], [4.243966, 0.182325], [4.453453, 0.200748], [4.654542, 0.218878], [4.868304, 0.238715], [5.070615, 0.254610], [5.288194, 0.272639], [5.494627, 0.287299], [5.723200, 0.303031], [5.931618, 0.315398], [6.189813, 0.316119], [6.384031, 0.328265], [6.658715, 0.327107], [6.855071, 0.333307], [7.138154, 0.331096], [7.334967, 0.338243], [7.625989, 0.335927], [7.820513, 0.343463], [8.077639, 0.339921], [8.264375, 0.349140], [8.473862, 0.344021], [8.652201, 0.349255], [8.816034, 0.346376], [8.944750, 0.345141], [9.079573, 0.344968], [9.130418, 0.344184], [9.255163, 0.342439], [9.195768, 0.345535], [9.247223, 0.344030], [9.192867, 0.345617], [9.281273, 0.337575] ] df = pd.DataFrame(data, columns=['X', 'y']) # 按X值排序,避免离散点顺序混乱导致求导错误 df = df.sort_values('X').reset_index(drop=True) x = df['X'].values y = df['y'].values # 1. 样条插值拟合平滑曲线,s参数控制平滑度,可根据实际效果调整 spl = UnivariateSpline(x, y, s=0.001) # 生成更密集的采样点用于求导和绘图 x_dense = np.linspace(x.min(), x.max(), 1000) y_smooth = spl(x_dense) # 2. 计算一阶导数 dy_dx = spl.derivative(n=1)(x_dense) # 3. 找到导数最大值的一半对应的坐标 max_deriv = dy_dx.max() half_max_deriv = max_deriv / 2 # 找到导数从低于半值到高于半值的交点位置 cross_idx = np.where(np.diff(np.sign(dy_dx - half_max_deriv)))[0][0] # 线性插值计算精确的X坐标 x_half = np.interp(half_max_deriv, dy_dx[cross_idx:cross_idx+2], x_dense[cross_idx:cross_idx+2]) y_half = spl(x_half) # 4. 可视化 plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8)) # 原始曲线 ax1.plot(x, y, 'o', label='原始离散点', markersize=3, alpha=0.6) ax1.plot(x_dense, y_smooth, label='拟合平滑曲线') ax1.scatter(x_half, y_half, c='red', s=50, zorder=5, label=f'导数半值点\nX={x_half:.2f}, y={y_half:.3f}') ax1.set_xlabel('X') ax1.set_ylabel('y') ax1.set_title('原始曲线及导数半值点') ax1.legend() ax1.grid(alpha=0.3) # 一阶导数曲线 ax2.plot(x_dense, dy_dx, label='一阶导数') ax2.axhline(max_deriv, c='green', linestyle='--', label=f'导数最大值={max_deriv:.3f}') ax2.axhline(half_max_deriv, c='orange', linestyle='--', label=f'导数半最大值={half_max_deriv:.3f}') ax2.scatter(x_half, half_max_deriv, c='red', s=50, zorder=5) ax2.set_xlabel('X') ax2.set_ylabel('dy/dx') ax2.set_title('一阶导数曲线') ax2.legend() ax2.grid(alpha=0.3) plt.tight_layout() plt.show() # 输出结果 print(f"一阶导数最大值为: {max_deriv:.4f}") print(f"导数达到最大值一半时对应的坐标点: X={x_half:.4f}, y={y_half:.4f}")
效果说明
原始曲线示意图如下:
运行代码后会输出两个可视化图表,同时打印目标坐标点的数值,可调整样条插值的s参数控制平滑度,匹配实际的曲线拟合需求。
内容的提问来源于stack exchange,提问作者the phoenix
相关产品推荐
相关产品推荐

