英文:
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:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。




评论