我是 python 的新手,想尝试将直方图拟合为“指数类”和“正态类”分布的总和。原则上,我想在已知的发行版上尝试这个,所有发行版都是用 scipi.stats 内置的。该过程将迭代
pdfs_start
中的每对函数和 pdfs_bulk
中的函数。
由于 scipi stat 中的 pdf 似乎不具有带有参数列表的属性(除了 *args),我检查了文档以构建函数,其功能如下
import inspect
from scipy.stats import norm, lognorm, expon, gamma, beta, pareto
from scipy.stats import kstest, chisquare
from scipy.optimize import curve_fit
def expon_func(x, exp1, exp2):
return expon.pdf(x, exp1, exp2)
expon_func.name = expon.name
def beta_func(x, beta1, beta2, beta3, beta4):
return beta.pdf(x, beta1, beta2, beta3, beta4)
beta_func.name = beta.name
def pareto_func(x, pareto1, pareto2, pareto3):
return pareto.pdf(x, beta1, beta2, beta3)
pareto_func.name = pareto.name
def norm_func(x, norm1, norm2):
return norm.pdf(x, norm1, norm2)
norm_func.name = norm.name
def lognorm_func(x, lognorm1, lognorm2, lognorm3):
return lognorm.pdf(x, lognorm1, lognorm2, lognorm3)
lognorm_func.name = lognorm.name
def gamma_func(x, gamma1, gamma2, gamma3):
return gamma.pdf(x, gamma1, gamma2, gamma3)
gamma_func.name = gamma.name
pdfs_start = [expon_func, beta_func, pareto_func]
pdfs_bulk = [norm_func, lognorm_func, gamma_func, beta_func]
我尝试了以下函数来执行传递一个新函数,该函数返回其两个参数函数的总和:
def create_func(f1, f2):
f1_params = list(inspect.signature(f1).parameters.keys())[1:]
f2_params = list(inspect.signature(f2).parameters.keys())[1:]
params = list(set(f1_params) | set(f2_params))
def func(x, *params):
return f1(x, *f1_params) + f2(x, *f2_params)
return {'Function': func, 'Name': f"{f1.name} + {f2.name}", 'p0': [1 for i in range(len(params))] }
请注意,两个列表的每个函数共享的唯一参数是自变量
x
。除了这个,每个函数都有不同数量的参数,我不想为每个组合手动指定。
字典中的“p0”条目将作为初始猜测提供给 curve_fit,否则它将无法确定拟合参数的数量。
调用 curve_fit 的一个例子是,然后(在实际情况下,它会在 for 循环中,但这里就足够了)
popt,_ = curve_fit(create_func(pdfs_start[2],pdfs_bulk[3])['Function'], bins[:-1] + (bins[1] - bins[0])/2, hist, p0 = create_func(pdfs_start[2],pdfs_bulk[3])['p0'])
这确实运行了,但是得到的曲线非常糟糕(很抱歉,我无法提供直方图)。我想这是一个数值问题,curve_fit 根本无法收敛这么多参数和给定的初始猜测,但我不确定。
我的打算能实现吗?除此之外,您有任何改进我的代码的技巧吗?我很感激任何见解!