clophfit.fitting.gain_calibration#

Calibrate a gain-only noise model from a fit’s own residuals, then refit.

Feasible generalised least squares with sigma^2 = floor^2 + gain * yhat and alpha held at 0: fit every well under the current weights, pool the residuals of all wells, estimate the gain (and optionally the floor), rebuild the weights, refit, and repeat until the noise terms stop moving. The pool is one plate or several; with several, one gain per label is shared by every plate and each plate keeps its own floor.

Two fitters plug into the same loop: the per-well least-squares fit (fit_binding_glob(), lm or huber) and the plate-wide fit_plate_lm().

Classes#

GainCalibration

What the calibration loop converged to, and the fits made under it.

Functions#

single_well_residuals(results)

Raw residuals of per-well fits, with each well's degrees-of-freedom factor.

plate_lm_residuals(result)

Raw residuals of a plate-wide fit, with the plate's degrees-of-freedom factor.

calibrate_gain(fit, floors, *[, fit_floor, gain_amp, ...])

Iterate fit -> pooled residuals -> floor and gain -> refit, to a fixed point.

calibrate_single_well(plates, floors, *[, method, ...])

Fit every well on its own, calibrating floor and gain across all of them.

calibrate_plate_lm(plates, groups, floors, *[, loss, ...])

Fit each plate jointly, calibrating floor and gain across all of them.

Module Contents#

class clophfit.fitting.gain_calibration.GainCalibration[T]#

What the calibration loop converged to, and the fits made under it.

fits#

Plate to its fit under noise, the weights the last pass used.

Type:

dict[str, T]

noise#

Plate to label to the floor and gain in force for fits; alpha is 0.

Type:

NoiseByPlate

history#

One row per pass, plate and label: iteration, plate, label, gain and sigma_floor in force for that pass, and n, the residuals that pass contributed.

Type:

pd.DataFrame

converged#

Whether the last adopted step moved every term by less than the tolerance. Damping halves a term’s step whenever it reverses, so a loop that oscillates settles between its two answers and still counts as converged; proposal_moved says whether that is a fixed point.

Type:

bool

proposal_moved#

Largest relative change the last undamped estimate asked for. Below the tolerance, the noise is a fixed point of fit -> estimate -> refit; above it, the loop settled by damping alone.

Type:

float

n_iter#

Fitting passes made.

Type:

int

clophfit.fitting.gain_calibration.single_well_residuals(results)#

Raw residuals of per-well fits, with each well’s degrees-of-freedom factor.

Parameters:

results (Mapping[str, FitResult]) – Well to its fit; wells without a result are skipped.

Returns:

well, label, yhat, raw_res and dof_scale (one value per well, from all its labels’ points and varied parameters).

Return type:

pd.DataFrame

clophfit.fitting.gain_calibration.plate_lm_residuals(result)#

Raw residuals of a plate-wide fit, with the plate’s degrees-of-freedom factor.

Parameters:

result (PlateLMResult) – A plate fit.

Returns:

well, label, yhat, raw_res and dof_scale.

Return type:

pd.DataFrame

clophfit.fitting.gain_calibration.calibrate_gain[T](fit, floors, *, fit_floor=False, gain_amp=None, max_iter=20, tol=0.001)#

Iterate fit -> pooled residuals -> floor and gain -> refit, to a fixed point.

The first pass weights each plate by its floor alone. Each later pass weights by the floor and gain the previous pass’s residuals gave, pooled over every well of every plate in floors. A term whose update reverses direction takes half the step from then on, which settles a loop that would otherwise cycle. The loop stops when no floor or gain moves by more than tol (relative), and returns the fits made under the weights that no longer move.

Parameters:
  • fit (Callable[[str, dict[str, NoiseModelParams]], tuple[T, pd.DataFrame]]) – Fits one plate under one noise model, returning the fit and its raw residual table (label, yhat, raw_res, dof_scale), as single_well_residuals() and plate_lm_residuals() build.

  • floors (Mapping[str, Mapping[str, float]]) – Plate to label to its read-noise floor, held unless fit_floor, and the only weights of the first pass either way.

  • fit_floor (bool) – Estimate each plate’s floor along with the shared gain.

  • gain_amp (Mapping[str, Mapping[str, float]] | None) – Plate to label to the amplification its gain scales with; the shared gain is quoted at 1. None shares the gain unscaled.

  • max_iter (int) – Most fitting passes.

  • tol (float) – Relative change below which the noise terms have converged.

Returns:

The last pass’s fits and the noise they were made under.

Return type:

GainCalibration[T]

Raises:

ValueError – If a pass leaves no residuals to calibrate from.

clophfit.fitting.gain_calibration.calibrate_single_well(plates, floors, *, method='lm', fit_floor=False, gain_amp=None, max_iter=20, tol=0.001, **fit_kwargs)#

Fit every well on its own, calibrating floor and gain across all of them.

Parameters:
  • plates (Mapping[str, Mapping[str, Dataset]]) – Plate to well to dataset. One plate calibrates that plate; several share one gain per label.

  • floors (Mapping[str, Mapping[str, float]]) – Plate to label to read-noise floor.

  • method (Literal["lm", "huber"]) – The per-well loss, passed to fit_binding_glob().

  • fit_floor (bool) – Estimate each plate’s floor as well as the gain.

  • gain_amp (Mapping[str, Mapping[str, float]] | None) – See calibrate_gain().

  • max_iter (int) – Most fitting passes.

  • tol (float) – Relative convergence tolerance on floor and gain.

  • **fit_kwargs (Any) – Forwarded to fit_binding_glob (e.g. remove_outliers).

Returns:

Per plate, well to its fit under the calibrated weights.

Return type:

GainCalibration[dict[str, FitResult]]

clophfit.fitting.gain_calibration.calibrate_plate_lm(plates, groups, floors, *, loss='linear', fit_floor=False, gain_amp=None, max_iter=20, tol=0.001)#

Fit each plate jointly, calibrating floor and gain across all of them.

Each pass is an ordinary fit_plate_lm() with the noise model fixed; the calibration happens between passes, so the fitter’s own calibrate_noise (gain and alpha, uncorrected for degrees of freedom) is not involved. The profiled ye_mag still rescales each label, and with a well-calibrated gain it should come out near 1.

Parameters:
  • plates (Mapping[str, Mapping[str, Dataset]]) – Plate to well to dataset.

  • groups (Mapping[str, Mapping[str, Sequence[str]]]) – Plate to its control groups (group name to member wells), which pool one K; an empty mapping fits every well its own K.

  • floors (Mapping[str, Mapping[str, float]]) – Plate to label to read-noise floor.

  • loss (Literal["linear", "huber", "soft_l1", "cauchy"]) – The plate fit’s loss.

  • fit_floor (bool) – Estimate each plate’s floor as well as the gain.

  • gain_amp (Mapping[str, Mapping[str, float]] | None) – See calibrate_gain().

  • max_iter (int) – Most fitting passes.

  • tol (float) – Relative convergence tolerance on floor and gain.

Returns:

Per plate, the plate fit under the calibrated weights.

Return type:

GainCalibration[PlateLMResult]