【问题标题】:Shifting a curve to another curve horizontally将一条曲线水平移动到另一条曲线
【发布时间】:2021-07-19 01:50:56
【问题描述】:

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

曲线数据:

   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]

【问题讨论】:

  • 重复橙色曲线的值,例如20次,就会被拉伸。
  • 我不认为我完全明白你在说什么。
  • 右移意味着用x1x2 替换x。然后你可以抵消你的 x 之一。那么当你的 x`s 不再对齐时,你就会遇到更难的问题来定义什么是合适的。

标签: python curve-fitting model-fitting


【解决方案1】:

为了使下面的矩阵方程更清晰,符号已更改:

y(x)=y1(x)

z(x)=y2(x)

value=c 在 x 对数刻度上的平移等价于 value=b 在 x 线性刻度上的扩展,因为 log(x)+c=log(bx) 和 c=log(b)。

反函数 x=f(y) 必须与 bx=f(z) 近似一致。所以我们考虑残差之和[f(y)-x]^2+[f(z)-b x]^2。这导致下面的回归演算。函数 f(y) 用 m 次多项式逼近。

对于给定的数据,f(y) 的曲线形状相当平滑。这表明低度数 m 可能就足够了。

例如 m=2 的结果是:

黑色曲线是在对数刻度上从 c=0.180 水平平移的蓝色曲线。

当然可以使用更高次的多项式。例如 m=3 我们得到 b=1.536 和 c=0.186

这个数值例子是一个有利的例子,因为曲线 x=f(y) 具有简单的形状。对于更复杂的形状,可能需要更大的 m 值,但存在回归演算不可靠的风险。

【讨论】:

    【解决方案2】:

    这个问题有一些问题需要一些技巧来解决。我敢肯定这不是理想的解决方案,但它提供了与手动方法所期望的值(大约 1.5 和 1.6)足够接近的值。

    第一个障碍是,当您移动 X 值时,您不会得到匹配的 y 值,因此计算残差可能会很棘手。我通过创建一个包含 1000 个点的巨大新 x 数组来强行解决这个问题,然后在这个新的 x 数组上插入原始的 2 个 y 值(稍后会出现)。因此,在计算两条曲线之间的残差时,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 的值。然后,我找到了原始索引和 shift 停止匹配的索引。

    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,来说明好的和坏的偏移值(这些是通过测试不同的值发现的)。垂直线表示该区域的共同点。

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

    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)

    【讨论】:

      猜你喜欢
      • 2015-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多