clophfit.fitting.noise_calibration#
Noise-model calibration from fit residuals.
Estimators that turn a canonical residual table into a
PlateNoiseModel: per-label floor,
photon gain, and proportional error, plus the plate slope helpers used to
propagate x-axis noise.
Functions#
|
Calibrate a per-label noise model from outlier-screened residuals. |
|
Estimate proportional error (alpha) per label via moment estimator. |
|
Estimate Poisson gain per label via moment estimator. |
|
Fit heteroscedastic noise model via non-negative least squares. |
|
Compute |dS/dpH| for the Henderson-Hasselbalch equation. |
|
Compute per-well per-label |
|
Fit global |
Module Contents#
- clophfit.fitting.noise_calibration.calibrate_noise_robust(residuals, sigma_floor, *, p_threshold=0.9, min_keep=3)#
Calibrate a per-label noise model from outlier-screened residuals.
Drops points whose posterior outlier probability exceeds p_threshold (from a PyMC mixture fit) and then estimates
gainandalphaper label with the single-term moment estimators (fit_gain_from_residuals(),fit_rel_error_from_residuals()) on the retained points. Screening with the mixture’sp_outlierkeeps outliers from inflating the estimate, while the two single-term estimators avoid the gain/alpha collinearity of the joint NNLS over narrow titration ranges.- Parameters:
residuals (pd.DataFrame) – Canonical residual table (e.g.
MultiFitResult.residualsfrom a mixture fit). Must havelabel,raw_res,yhatcolumns; ap_outliercolumn enables screening (otherwise all points are used).sigma_floor (dict[str, float]) – Known read-noise floor per label, e.g.
tit.bg_noise. Used as the fixed floor and copied into the returned model.p_threshold (float, optional) – Posterior outlier probability above which a point is dropped.
min_keep (int, optional) – Per label, if screening would retain fewer than this many points the full (unscreened) set is used instead.
- Returns:
Per-label model with
sigma_floorfrom sigma_floor and calibratedgain/alpha.- Return type:
- clophfit.fitting.noise_calibration.fit_rel_error_from_residuals(df, sigma_floor)#
Estimate proportional error (alpha) per label via moment estimator.
Assumes the simplified noise model
sigma^2 = floor^2 + alpha^2 * yhat^2(no Poisson gain term). Withfloorknown from buffer measurements and using model-predicted valuesyhatin the denominator to avoid noise-in-variables bias, the closed-form moment estimator is:\[\hat{\alpha}^2 = \frac{\overline{r^2} - \sigma_{\text{floor}}^2}{\overline{\hat{y}^2}}\]- Parameters:
df (pd.DataFrame) – DataFrame with columns
label(str),raw_res(float), andyhat(float – the model-predicted signal at each point). Typically fromclophfit.fitting.model_validation.residuals_from_fit_results().sigma_floor (dict[str, float]) – Known read-noise floor per label, e.g. from
tit.bg_noise.
- Returns:
Per-label proportional error estimate
alpha(non-negative).- Return type:
dict[str, float]
Examples
>>> import numpy as np, pandas as pd >>> rng = np.random.default_rng(0) >>> y_pred = np.linspace(50, 500, 200) >>> floor, true_alpha = 5.0, 0.02 >>> sigma = np.sqrt(floor**2 + (true_alpha * y_pred) ** 2) >>> resid = sigma * rng.standard_normal(200) >>> df = pd.DataFrame({"label": "1", "raw_res": resid, "yhat": y_pred}) >>> alpha = fit_rel_error_from_residuals(df, sigma_floor={"1": floor}) >>> round(alpha["1"], 2) # should be close to true_alpha=0.02 0.02
- clophfit.fitting.noise_calibration.fit_gain_from_residuals(df, sigma_floor)#
Estimate Poisson gain per label via moment estimator.
Symmetric counterpart to
fit_rel_error_from_residuals(). Assumes the Poisson-only noise modelsigma^2 = floor^2 + gain * yhat(no proportional term), which sidesteps the gain/alpha collinearity of the joint fit. Withfloorknown from buffer measurements and using model-predicted valuesyhat, the closed-form moment estimator is:\[\hat{\text{gain}} = \frac{\overline{r^2} - \sigma_{\text{floor}}^2}{\overline{\hat{y}}}\]- Parameters:
df (pd.DataFrame) – DataFrame with columns
label(str),raw_res(float), andyhat(float – the model-predicted signal at each point). Typically fromclophfit.fitting.model_validation.residuals_from_fit_results().sigma_floor (dict[str, float]) – Known read-noise floor per label, e.g. from
tit.bg_noise.
- Returns:
Per-label Poisson gain estimate (non-negative).
- Return type:
dict[str, float]
Examples
>>> import numpy as np, pandas as pd >>> rng = np.random.default_rng(0) >>> y_pred = np.linspace(50, 500, 400) >>> floor, true_gain = 5.0, 0.8 >>> sigma = np.sqrt(floor**2 + true_gain * y_pred) >>> resid = sigma * rng.standard_normal(400) >>> df = pd.DataFrame({"label": "1", "raw_res": resid, "yhat": y_pred}) >>> gain = fit_gain_from_residuals(df, sigma_floor={"1": floor}) >>> round(gain["1"], 1) # should be close to true_gain=0.8 0.8
- clophfit.fitting.noise_calibration.fit_noise_model_nnls(df, sigma_floor_fixed=None, rel_error_fixed=None)#
Fit heteroscedastic noise model via non-negative least squares.
Model: \(\sigma^2 = \sigma_\text{floor}^2 + \text{gain} \cdot y + \alpha^2 \cdot y^2\)
Uses
scipy.optimize.nnls()to enforce non-negativity on all parameters, which stabilises estimates when \(y\) and \(y^2\) are highly collinear (typical for narrow-range titrations).- Parameters:
df (pd.DataFrame) – Residual DataFrame with columns
label,raw_res,yhat.sigma_floor_fixed (dict[str, float] | None) – If given, fix floor per label and only fit gain and alpha.
rel_error_fixed (dict[str, float] | None) – If given, fix alpha per label and only fit floor and gain.
- Returns:
(sigma_floor, gain, alpha)per label — all non-negative.- Return type:
tuple[dict[str, float], dict[str, float], dict[str, float]]
- Raises:
ValueError – If both sigma_floor_fixed and rel_error_fixed are provided.
- clophfit.fitting.noise_calibration.compute_binding_slope(ph, pka, s0, s1)#
Compute |dS/dpH| for the Henderson-Hasselbalch equation.
dS/dpH = (s1 - s0) * ln(10) * t / (1 + t)^2wheret = 10^(pka - ph). Returns the absolute value (sign irrelevant for variance).- Parameters:
ph (numpy.ndarray)
pka (float)
s0 (float)
s1 (float)
- Return type:
numpy.ndarray
- clophfit.fitting.noise_calibration.compute_plate_slopes(results)#
Compute per-well per-label
∂S/∂pHfrom pass-1 fit results.- Parameters:
results (dict[str, Any]) – Fit results keyed by well (must have
.resultand.dataset).- Returns:
{well: {label: slope_array}}.- Return type:
dict[str, dict[str, np.ndarray]]
- clophfit.fitting.noise_calibration.fit_ph_slope_noise(df, noise_model, plate_slopes)#
Fit global
sigma_phfrom excess variance after per-label model.After subtracting the per-label noise model variance, the leftover
r^2 - var_modelis regressed against(dS/dpH)^2via NNLS.- Parameters:
df (pd.DataFrame) – Residual DataFrame with columns
label,well,raw_res,yhat, andraw_i.noise_model (PlateNoiseModel) – Per-label noise model (floor, gain, alpha) fitted in the same pass.
plate_slopes (dict[str, dict[str, np.ndarray]]) – Per-well per-label derivative
|dS/dpH|arrays.
- Returns:
Global
sigma_phestimate (>= 0).- Return type:
float