gpt4 book ai didi

python - 将曲线拟合到散点图的边界

转载 作者:太空狗 更新时间:2023-10-29 20:58:10 28 4
gpt4 key购买 nike

我正在尝试将曲线拟合到散点图的边界。 See this image for reference . enter image description here

我已经使用以下(简化的)代码完成了匹配。它将数据帧切成小的垂直 strip ,然后在这些宽度为 width 的 strip 中找到最小值,忽略 nan。 (函数单调递减。)

def func(val):
""" returns some function of 'val'"""
return val * 2

for i in range(0, max_val, width)):
_df = df[(df.val > i) & (df.val < i + width)] # vertical slice
if np.isnan(np.min(func(_df.val)): # ignore nans
continue
xs.append(i + width)
ys.append(np.min(func(_df.val)))

然后我使用 scipy.optimize.curve_fit 进行拟合。我的问题是:是否有更自然或 pythonic 的方法来做到这一点——有什么方法可以提高准确性吗? (例如,通过对点密度较高的散点图区域给予更高的权重?)

最佳答案

我发现这个问题很有趣,所以我决定试一试。我不知道 pythonic 或 natural,但我认为我找到了一种更准确的方法,可以在使用来自每个点的信息时将边缘拟合到像您这样的数据集。

首先,让我们生成一个看起来像您显示的数据的随机数据。这部分可以很容易地跳过,我发布它只是为了使代码完整和可重现。我使用了两个双变量正态分布来模拟这些超密度,并在它们上面撒上一层均匀分布的随机点。然后将它们添加到类似于您的线方程中,线下方的所有内容都被切断,最终结果如下所示: making of the data

这是实现它的代码片段:

import numpy as np

x_res = 1000
x_data = np.linspace(0, 2000, x_res)

# true parameters and a function that takes them
true_pars = [80, 70, -5]
model = lambda x, a, b, c: (a / np.sqrt(x + b) + c)
y_truth = model(x_data, *true_pars)

mu_prim, mu_sec = [1750, 0], [450, 1.5]
cov_prim = [[300**2, 0 ],
[ 0, 0.2**2]]
# covariance matrix of the second dist is trickier
cov_sec = [[200**2, -1 ],
[ -1, 1.0**2]]
prim = np.random.multivariate_normal(mu_prim, cov_prim, x_res*10).T
sec = np.random.multivariate_normal(mu_sec, cov_sec, x_res*1).T
uni = np.vstack([x_data, np.random.rand(x_res) * 7])

# censoring points that will end up below the curve
prim = prim[np.vstack([[prim[1] > 0], [prim[1] > 0]])].reshape(2, -1)
sec = sec[np.vstack([[sec[1] > 0], [sec[1] > 0]])].reshape(2, -1)

# rescaling to data
for dset in [uni, sec, prim]:
dset[1] += model(dset[0], *true_pars)

# this code block generates the figure above:
import matplotlib.pylab as plt
plt.figure()
plt.plot(prim[0], prim[1], '.', alpha=0.1, label = '2D Gaussian #1')
plt.plot(sec[0], sec[1], '.', alpha=0.5, label = '2D Gaussian #2')
plt.plot(uni[0], uni[1], '.', alpha=0.5, label = 'Uniform')
plt.plot(x_data, y_truth, 'k:', lw = 3, zorder = 1.0, label = 'True edge')
plt.xlim(0, 2000)
plt.ylim(-8, 6)
plt.legend(loc = 'lower left')
plt.show()

# mashing it all together
dset = np.concatenate([prim, sec, uni], axis = 1)

现在我们有了数据和模型,我们可以集思广益如何拟合点分布的边缘。非线性最小二乘 scipy.optimize.curve_fit 等常用回归方法采用数据值 y 并优化模型的自由参数,以便 之间的残差ymodel(x) 是最小的。非线性最小二乘法是一个迭代过程,它试图在每一步摆动曲线参数以改进每一步的拟合。现在很明显,这是我们不想做的一件事,因为我们希望我们的最小化例程使我们尽可能远离最佳拟合曲线(但< 很远)。

因此,让我们考虑以下函数。不是简单地返回残差,它还会在迭代的每一步“翻转”曲线上方的点并将它们也考虑在内。这样一来,曲线下方的点总是比上方的点多,导致曲线在每次迭代中都向下移动!一旦达到最低点,就会找到函数的最小值,散布的边缘也是如此。当然,此方法假设您在曲线下方没有异常值 - 但您的数字似乎并没有受到太大影响。

下面是实现这个想法的函数:

def get_flipped(y_data, y_model):
flipped = y_model - y_data
flipped[flipped > 0] = 0
return flipped

def flipped_resid(pars, x, y):
"""
For every iteration, everything above the currently proposed
curve is going to be mirrored down, so that the next iterations
is going to progressively shift downwards.
"""
y_model = model(x, *pars)
flipped = get_flipped(y, y_model)
resid = np.square(y + flipped - y_model)
#print pars, resid.sum() # uncomment to check the iteration parameters
return np.nan_to_num(resid)

让我们看看上面的数据是怎样的:

# plotting the mock data
plt.plot(dset[0], dset[1], '.', alpha=0.2, label = 'Test data')

# mask bad data (we accidentaly generated some NaN values)
gmask = np.isfinite(dset[1])
dset = dset[np.vstack([gmask, gmask])].reshape((2, -1))

from scipy.optimize import leastsq
guesses =[100, 100, 0]
fit_pars, flag = leastsq(func = flipped_resid, x0 = guesses,
args = (dset[0], dset[1]))
# plot the fit:
y_fit = model(x_data, *fit_pars)
y_guess = model(x_data, *guesses)
plt.plot(x_data, y_fit, 'r-', zorder = 0.9, label = 'Edge')
plt.plot(x_data, y_guess, 'g-', zorder = 0.9, label = 'Guess')
plt.legend(loc = 'lower left')
plt.show()

上面最重要的部分是对leastsq函数的调用。确保您对最初的猜测很小心 - 如果猜测没有落在散点上,模型可能无法正确收敛。在进行适当的猜测之后...

ifitfitsisits

瞧!边缘与真实边缘完美匹配。

关于python - 将曲线拟合到散点图的边界,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37800958/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com