湖泊营养收支数据曲线拟合结果不一致问题排查
背景
我有一组湖泊营养收支数据集(来自文献整理并公开),包含三个变量:
Lin:湖泊营养输入通量(单位:吨/年)Lout:湖泊营养输出通量(单位:吨/年)tau:水体滞留时间(单位:年)
理论上三者满足关系:
Lout = Lin / (1 + sigma*(tau**n))
其中sigma和n为待求经验常数。
三种拟合尝试
尝试1:直接用lmfit拟合原公式
代码:
import numpy as np import pandas as pd import statsmodels.formula.api as smf from lmfit import Model data_url = r"https://gist.githubusercontent.com/JamesSample/029f59471818929ef9fb87bde95169bc/raw/c5b66b554b9ff9d3c448a80c0b4104f410ab5185/lake_n_budgets.csv" df = pd.read_csv(data_url) df.head() def load_out(Lin, tau, sigma=1, n=1): return Lin / (1 + (sigma * (tau**n))) model = Model(load_out, independent_vars=["Lin", "tau"]) fit = model.fit(df["Lout"], Lin=df["Lin"], tau=df["tau"]) fit
得到参数:sigma=0.382,n=0.160
尝试2:拟合传输因子公式
基于文献常用的传输因子trans = Lout/Lin,拟合公式:
trans = 1/(1 + sigma*(tau**n))
代码:
def transmission(tau, sigma=1, n=1): return 1 / (1 + (sigma * (tau**n))) df["trans"] = df["Lout"] / df["Lin"] model = Model(transmission, independent_vars=["tau"]) fit = model.fit(df["trans"], tau=df["tau"]) fit
得到参数:sigma=0.799,n=0.313,与尝试1结果差异显著。
尝试3:对数变换后线性回归
将公式变形为y = (Lin/Lout) - 1,则log10(y) = log10(sigma) + n*log10(tau),用statsmodels做线性回归:
代码:
df["y"] = (df["Lin"] / df["Lout"]) - 1 mod = smf.ols(formula='np.log10(y) ~ np.log10(tau)', data=df) res = mod.fit() print(res.summary()) print() print("Estimate for sigma:", 10**res.params[0]) print("Estimate for n:", res.params[1])
得到参数:sigma≈0.757,n≈0.361,与尝试2结果一致。
注:使用完全匹配理论关系的合成数据集时,三种方法结果一致,代码逻辑正确。
疑问
- 这种结果差异是否合理,还是我忽略了明显问题?
- 参数的不确定度为何小于不同拟合方式的结果差异?
- 尝试1的lmfit代码是否存在bug?
- 尝试1是否存在根本性错误?
- 结果差异是否说明该模型不适用于我的数据集?
解答
1. 结果差异合理,核心原因是拟合时的权重/误差结构不同
三种方法本质是对不同因变量做拟合,假设的误差分布不一致:
- 尝试1:直接拟合
Lout,默认假设Lout的绝对误差是同方差高斯分布(即大Lin对应的Lout误差和小Lin的误差量级一致)。但生态数据中,Lout的绝对误差通常随Lin增大而增加,相对误差更稳定。 - 尝试2/3:拟合
trans或对数变换后的变量,等价于假设相对误差同方差,这更符合这类数据的实际规律。
当拟合假设的误差结构与数据实际误差不匹配时,就会得到不同的参数估计,这是统计拟合中的常见现象。
2. 参数不确定度是方法内的统计波动,而非方法间的假设差异
每个拟合方法给出的不确定度,是基于自身误差假设计算的(比如尝试1的不确定度是假设Lout同方差下的参数波动),但不同方法的差异来自模型假设的系统性偏差,而非随机噪声。前者是“同一假设下的波动”,后者是“不同假设的偏差”,因此不确定度自然小于方法间的差异。
3. 尝试1的代码无bug
你的lmfit代码逻辑完全正确:模型函数定义准确,独立变量指定清晰,数据传入符合要求。合成数据下的一致结果也验证了代码没有问题。
4. 尝试1无根本性错误,但误差假设可能不符合数据实际
尝试1的拟合逻辑成立,但默认的“绝对误差恒定”假设可能不适合你的数据。普通最小二乘拟合中,每个数据点权重相同,大Lin对应的Lout数值大,残差绝对值也会更大,拟合时会优先减小这些大残差,导致参数偏向大Lin的样本特征;而尝试2/3对相对值拟合,每个数据点的权重更均衡,结果更符合整体数据的规律。
5. 结果差异不能直接说明模型不适用于数据集
合成数据下三种方法结果一致,证明模型本身是自洽的。差异根源是拟合时的误差假设与数据实际误差结构不匹配,而非模型本身不适用。你可以通过以下方式验证:
- 查看尝试1中
Lout的残差是否随Lin增大而增大; - 查看尝试2中
trans的残差是否更均匀; - 给尝试1的每个数据点赋予
1/Lin的权重(抵消绝对误差的影响),再观察参数是否收敛到尝试2/3的结果。
如果加权后参数与尝试2/3一致,说明模型是适用的,只需选择匹配数据误差结构的拟合方式即可。
内容的提问来源于stack exchange,提问作者JamesS

