python - 将一条曲线水平移动到另一条曲线

标签 python curve-fitting model-fitting

有谁知道如何将一条曲线拟合到另一条曲线,只需将其向右移动即可。例如,在此图中,我想将橙色曲线向右移动(没有垂直移动!)以使曲线彼此重叠。谁能帮我做到这一点?

Plot

曲线数据:

   y1 = [1.2324, 1.4397, 1.5141, 1.7329, 1.9082, 2.2884, 2.166, 2.8175, 3.1014, 2.8893, 3.673, 4.3875, 4.9817, 5.6906, 6.3667, 7.2854, 8.2703, 9.3432, 10.591, 11.963, 13.579, 15.36, 17.306, 19.508, 21.976, 24.666, 27.692, 31.026, 34.724, 38.702]
        
   y2 = [1.6231, 1.6974, 1.8145, 2.4805, 2.5643, 2.6176, 2.9332, 3.4379, 4.0154, 4.2258, 4.6837, 5.9837, 6.4408, 7.2903, 8.2283, 9.4134, 10.537, 11.947, 13.344, 15.202, 17.073, 19.211, 21.598, 24.216, 27.06, 30.31, 33.933, 37.882, 42.201, 46.978]
    
    x = [0.1, 0.127, 0.161, 0.204, 0.259, 0.329, 0.418, 0.53, 0.672, 0.853, 1.08, 1.37, 1.74, 2.21, 2.81, 3.56, 4.52, 5.74, 7.28, 9.24, 11.7, 14.9, 18.9, 24.0, 30.4, 38.6, 48.9, 62.1, 78.8, 100.0]

最佳答案

这个问题有一些需要摆弄才能解决的问题。我确信这不是理想的解决方案,但它提供的值足够接近手动方法的预期值(大约 1.5 和 1.6)。

第一个障碍是,当您移动 X 值时,您不会获得匹配的 y 值,因此计算残差可能会很棘手。我通过创建一个包含 1000 个点的巨大的新 x 数组,然后在这个新的 x 上插入原始的 2 个 y 值来强行解决这个问题。 code> array(稍后会介绍)。因此,在计算两条曲线之间的残差时,x 值将会偏离,但偏离幅度不大。

reference_y = y1
to_shift_y = y2
expanded_x = np.logspace(np.log10(x[0]), np.log10(x[-1]), num=1000)
expanded_y_reference = np.interp(expanded_x, x, reference_y)
expanded_y_to_shift = np.interp(expanded_x, x, to_shift_y)

然后,当您将 x 移动某个常量时,您将得到两个不存在等效 x 值的区域。

original x: -------------------------------xxxx
shifted x:  xxxx-------------------------------

我使用shift参数创建了一个新的x数组,hor_shift设置了一些大于1的值。然后,我找到了原始和移位停止匹配的索引.

start = np.argmax(expanded_x >= expanded_x_shifted[0])
end = np.argmin(expanded_x_shifted <= expanded_x[-1])

由于这些数组是 [False, False, True, True ...][True, True, ..., True, False, False]argmaxargmin 将返回具有不同值的第一个实例。

现在,我们必须对原始和移位的 x 数组进行切片,以便它们具有相同的大小和共同的值,并且与扩展的 y 数组相同。请原谅我的名字太长,这样我就不会感到困惑。

expanded_x_original_in_common_with_shifted = expanded_x[start:]
expanded_x_shifted_in_common_with_original = expanded_x_shifted[:end]
sliced_expanded_y_reference = expanded_y_reference[start:]
sliced_expanded_y_to_shift = expanded_y_to_shift[:end]

最后,也是最重要的,假设 x 值对齐,我们可以计算两条曲线之间的距离。

residual = ((sliced_expanded_y_reference - sliced_expanded_y_to_shift) ** 2).sum()

通过最小化这个,我们可以获得理想的转变。

我们可以比较我们的曲线。在这里,我使用了两个偏移值,1.3 和 1.56,来说明好的和坏的偏移值(这些值是通过测试不同的值发现的)。垂直线显示共同区域。

First Second

现在,我们可以将这个过程转化为一个函数,并使用一些最小化方法来找到理想的平移值。这是我得到的。

from lmfit import Parameters, minimize
par = Parameters()
# If the shift parameter is 1, you get an error
par.add('shift', value=1.1, min=1)

def min_function(par, x, reference_y, to_shift_y):
    hor_shift = par['shift'].value
    # print(hor_shift)  # <- in case you want to follow the process
    expanded_x = np.logspace(np.log10(x[0]), np.log10(x[-1]), num=1000)
    expanded_x_shifted = expanded_x * hor_shift
    start = np.argmax(expanded_x >= expanded_x_shifted[0])
    end = np.argmin(expanded_x_shifted <= expanded_x[-1])
    expanded_x_original_in_common_with_shifted = expanded_x[start:]
    expanded_x_shifted_in_common_with_original = expanded_x_shifted[:end]
    expanded_y_reference = np.interp(expanded_x, x, reference_y)
    expanded_y_to_shift = np.interp(expanded_x, x, to_shift_y)

    sliced_expanded_y_reference = expanded_y_reference[start:]
    sliced_expanded_y_to_shift = expanded_y_to_shift[:end]
    
    
    residual = ((sliced_expanded_y_reference - sliced_expanded_y_to_shift) ** 2).sum()
    return residual

minimize(min_function, par, method='nelder', args=(x, reference_y, to_shift_y))

这导致理想的平移参数为 1.555,证实了最初的猜测。请注意,如果您希望卡方与图表中的卡方匹配,则必须将residual 表达式更改为(sliced_expanded_y_reference - sliced_expanded_y_to_shift)

关于python - 将一条曲线水平移动到另一条曲线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67253931/

相关文章:

python - 如何在VScode中设置jupyter的运行文件路径?

python - Caffe中的net.layers.blobs和net.params有什么区别

python - 正则表达式以匹配 Python 中设置的 rar 存档文件中的第一个文件

python - 如何从多项式拟合中提取导数?

MATLAB - 曲线拟合 1/x 函数

r - 使用 nls 函数错误拟合

r - 在 r 中拟合模型时, "~."和 "~1"之间有什么区别?

Python3 添加日志级别

python - 洛伦兹拟合两种编写代码的方式

python - 为什么 curve_fit 对于 beta 函数拟合不收敛?