英文:
4-parameter logistic curve fit
问题
我正在尝试使用scipy对来自科学试验的数据执行4参数 logistic (4PL) 曲线拟合。目标是获得一个与我通常使用的软件结果密切匹配的拟合曲线。
不幸的是,曲线的下部拟合效果不佳,如下图所示。
我还尝试了在对x值应用log10变换后创建拟合,但只得到一条直线而不是曲线拟合。
以下是我的当前代码:
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize as opt
from scipy.optimize import curve_fit
conc = np.array([300000, 70376.8, 16509.6, 3873.0, 908.6, 213.1, 50.0, 11.7])
ref = np.array([7.11469e+05, 2.16006e+05, 5.81840e+04, 1.39850e+04,
3.21300e+03, 8.76000e+02, 2.54000e+02, 1.16000e+02])
# 4PL曲线方程
def func(xdata, a, b, c, d):
return ((a-d)/(1.0+((xdata/c)**b))) + d
# 计算示例权重为1/y^2
weights = 1 / (ref **2)
# 设置边界
amin = 50
bounds = ([ amin, -np.inf, -np.inf , -np.inf], [np.inf, np.inf, np.inf, np.inf])
# 初始参数
a = min(ref) * 0.9
d = max(ref) * 1.1
b = 1
c = (d-a)/2
initial_guess = [a, b, c, d]
print('初始参数:', initial_guess)
# 执行曲线拟合
params, params_covariance = curve_fit(func, conc, ref, p0=initial_guess, method='trf',sigma=weights, bounds=bounds, maxfev=100000)
print('参数:', params)
# 从拟合曲线生成y值
x_fit = np.arange(min(conc), max(conc), 8)
y_fit = func(x_fit, *params)
# 绘制原始数据和拟合曲线
plt.scatter(conc, ref , label='加权数据')
plt.plot(x_fit, y_fit, label='拟合曲线')
plt.xscale('log')
plt.yscale('log')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.show()
英文:
I am trying to perform a 4-parameter logistic (4PL) curve fit with scipy on data from a scientific assay. The goal is to get a fit that closely matches the results of the software I normally use.
Unfortunately, the lower part of the curve does not fit well, as shown in this figure.
I also tried to create a fit after applying a log10 transform to the x values, but I only get a straight line instead of a curve fit.
Below is my current code:
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize as opt
from scipy.optimize import curve_fit
conc = np.array([300000, 70376.8, 16509.6, 3873.0, 908.6, 213.1, 50.0, 11.7])
ref = np.array([7.11469e+05, 2.16006e+05, 5.81840e+04, 1.39850e+04,
3.21300e+03, 8.76000e+02, 2.54000e+02, 1.16000e+02])
# 4pl curve equation
def func(xdata, a, b, c, d):
return ((a-d)/(1.0+((xdata/c)**b))) + d
# Calculate example weights as 1/y^2
weights = 1 / (ref **2)
#set bounds
amin = 50
bounds = ([ amin, -np.inf, -np.inf , -np.inf], [np.inf, np.inf, np.inf, np.inf])
# initial params
a = min(ref) * 0.9
d = max(ref) * 1.1
b = 1
c = (d-a)/2
initial_guess = [a, b, c, d]
print('Initial params:', initial_guess)
# # Perform the curve fit
params, params_covariance = curve_fit(func, conc, ref, p0=initial_guess, method='trf',sigma=weights, bounds=bounds, maxfev=100000)
print('params:', params)
# Generate y values from the fitted curve
x_fit = np.arange(min(conc), max(conc), 8)
y_fit = func(x_fit, *params)
# # Plot the raw data and the fitted curve
#plt.scatter(conc_mlt, ref, label='Raw data')
plt.scatter(conc, ref , label='Weighted Data') #s=weights*100??
plt.plot(x_fit, y_fit, label='Fitted Curve')
plt.xscale('log')
plt.yscale('log')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.show()
答案1
得分: 1
我目前不确定如何使用scipy
来改进你的低值拟合。然而,如果你不需要使用特定的拟合函数,你可以考虑使用numpy.polyfit
等其他选项。以下是一个示例,以防这对你有用:
import numpy as np
import matplotlib.pyplot as plt
conc = np.array([300000, 70376.8, 16509.6, 3873.0, 908.6, 213.1, 50.0, 11.7])
ref = np.array([7.11469e+05, 2.16006e+05, 5.81840e+04, 1.39850e+04,
3.21300e+03, 8.76000e+02, 2.54000e+02, 1.16000e+02])
## Trying NumPy Polyfit
np_fit = np.poly1d(np.polyfit(np.log(conc), np.log(ref), deg=4))
x_npfits = np.logspace(1, 6)
y_npfits = []
for i in x_npfits:
y_npfits.append(np.exp(np_fit(np.log(i))))
plt.figure()
plt.scatter(conc, ref , label='Weighted Data')
plt.plot(x_npfits, y_npfits)
plt.xscale('log')
plt.yscale('log')
plt.grid("both")
plt.show()
生成:
英文:
I'm currently unsure of how to improve the fit of your lower values using scipy
. However, if you don't require the use of your specific fitting function, you could potentially look at options like numpy.polyfit
. Here is an example in case this could work for you:
import numpy as np
import matplotlib.pyplot as plt
conc = np.array([300000, 70376.8, 16509.6, 3873.0, 908.6, 213.1, 50.0, 11.7])
ref = np.array([7.11469e+05, 2.16006e+05, 5.81840e+04, 1.39850e+04,
3.21300e+03, 8.76000e+02, 2.54000e+02, 1.16000e+02])
## Trying NumPy Polyfit
np_fit = np.poly1d(np.polyfit(np.log(conc), np.log(ref), deg=4))
x_npfits = np.logspace(1, 6)
y_npfits = []
for i in x_npfits:
y_npfits.append(np.exp(np_fit(np.log(i))))
plt.figure()
plt.scatter(conc, ref , label='Weighted Data')
plt.plot(x_npfits, y_npfits)
plt.xscale('log')
plt.yscale('log')
plt.grid("both")
plt.show()
Produces:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论