Hello, @Byungchul_Yu !
I took a closer look at the implementation of TH1::Fit method when option "WL" is specified.
The relevant code is inside ROOT::Fit::FitUtil::EvaluatePoissonLogL.
I will try to address your questions.
Math derivation
Firstly, let’s map variables from the code to analytical quantities using your designations.
// FitUtil.cxx
// bin content: y_i = sum w
auto y = *data.ValuePtr(i);
// model prediction: mu_i
fval = func(x, p);
// standard deviation: sigma_i = sqrt(sum w^2)
double error = data.Error(i);
// effective weight or scale factor: s_i = sigma_i^2 / y_i
weight = (error * error) / y;
Following Böhm & Zech, a weighted bin content Y_i distribution can be modeled via a Scaled Poisson Distribution (SPD):
Y_i = s_{i, \text{true}} X_i, \, X_i \sim \text{Pois}(n_\text{eff,true})
where bin statistics are
y_i = \sum_{j} w_j, \quad \sigma_i^2 = \sum_{j} w_j^2
The estimated effective parameters are:
s_i = \frac{\sigma_i^2}{y_i},\quad n_\text{eff} = \frac{y_i^2}{\sigma_i^2} = \frac{y_i}{s_i},\quad \mu_\text{eff} = \frac{\mu_i}{s_i}
where \mu_i is model prediction for bin content.
The effective Poisson log-likelihood (dropping factorial term) is
l(\mu_\text{eff} \mid n_\text{eff}) = n_\text{eff} \log(\mu_\text{eff}) - \mu_\text{eff}
The Poisson deviance is
\Delta l = l(n_\text{eff} \mid n_\text{eff}) - l(\mu_\text{eff} \mid n_\text{eff}) = n_\text{eff} \log\frac{n_\text{eff}}{\mu_\text{eff}} - n_\text{eff} + \mu_\text{eff}
We can factor out s_i^{-1} by substituting back n_\text{eff} = y_i/s_i,\, \mu_\text{eff} = \mu_i/s_i
\begin{align*}
\Delta l &= \frac{y_i}{s_i} \log\frac{y_i}{\mu_i} - \frac{y_i}{s_i} + \frac{\mu_i}{s_i} =\\
&= \frac{1}{s_i} \times \left( -y_i \log\frac{\mu_i}{y_i} + \mu_i - y_i \right)
\end{align*}
Now compare to ROOT::Fit::FitUtil::EvaluatePoissonLogL implementation:
// FitUtil.cxx
// parts of log-likelihood calculation
nloglike -= weight * y * ( ROOT::Math::Util::EvalLog(fval/y) );
nloglike += weight * ( fval - y);
Since \mathtt{weight} = s_i, ROOT computes
\Delta l_\text{ROOT} = s_i \times \left( -y_i \log\frac{\mu_i}{y_i} + \mu_i - y_i \right)
In the limit (y_i - \mu_i) \ll \mu_i the correct deviance yields weighted Pearson’s \chi^2:
\Delta l \approx s_i^{-1} \left( -y_i \left(- \frac{y_i - \mu_i}{\mu_i} \right ) + \mu_i - y_i \right) = \frac{y_i}{\sigma_i^2} \times \frac{(y_i - \mu_i)^2}{\mu_i} \approx \frac{(y_i - \mu_i)^2}{\sigma_i^2}
For ROOT’s implementation, the limit becomes
\Delta l_\text{ROOT} \approx \frac{\sigma_i^2}{y_i} \times \frac{(y_i - \mu_i)^2}{\mu_i}
This inverts statistical weights: for example, large effective weights (s_i > 1) indicate overdispersion compared to Poisson distribution.
Such bins should have a reduced impact on objective function to minimize, but instead it is amplified.
Addressing questions
To sum up, regarding your first question, effective Poisson deviance is sufficient.
Regarding your second question, dropping s_i^{-1} factor (not s_i) yields basic Poisson deviance which disregards the variance of the weights inside bin.
It will produce biased point estimates with increased variance.
Also it will likely underestimate or overestimate error bounds if s_i > 1 or s_i < 1 over all bins.
Notably, I see that ROOT applies sandwich correction to covariance matrix in Fitter::ApplyWeightCorrection which fixes error bounds, but this doesn’t fix bias and increased variance of point estimates.
Possible bug
@StephanH and @jonas ,
I suspect that in the implementation inside ROOT::Fit::FitUtil::EvaluatePoissonLogL might be wrong.
Instead of
// FitUtil.cxx
// parts of log-likelihood calculation
nloglike -= weight * y * ( ROOT::Math::Util::EvalLog(fval/y) );
nloglike += weight * ( fval - y);
it should be
// FitUtil.cxx
// parts of log-likelihood calculation
nloglike -= (1.0/weight) * y * ( ROOT::Math::Util::EvalLog(fval/y) );
nloglike += (1.0/weight) * ( fval - y);
This behavior with multiplying log-likelihood with wrong prefactor appears both in v6.34.04 and v6.40.02.
If this is truly unintended, it might seriously affect fit convergence and quality in case of large weight variances inside bins.
Please let me know if I am missing something important in ROOT’s implementation.