Repository navigation
PiecewiseCF
CLI: --model piecewise_cf. Default since v0.3.0 (DEFAULT_MODEL in loqculate/config.py). Class: loqculate.models.piecewise_cf.PiecewiseCF.
I use this as the default because the mean function is the same piecewise line as PiecewiseWLS, and the knot is chosen by a search I can state, not by where TRF happened to stop.
params_ after a successful fit():
-
slope($a$ ) -
intercept_linear($b$ ) -
intercept_noise($c$ ) -
knot_x(partition used for the linear/noise split)
predict(x) returns max(c, a*x + b).
If you do not pass weights, fit() calls inverse_sqrt_weights:
np.finfo(float).eps. Cap is DEFAULT_WEIGHT_CAP = 1000. Precision weights used in the knot search are weights_ is
This is not exactly
fit() requires at least 3 observations. find_knot then requires at least 3 unique ValueError.
First pass. Candidates are unique(x)[1:-1] (interior unique concentrations). At each candidate
- if
$a < 0$ , set$a=0$ and replace the linear fit with a weighted mean - if
$c < b$ , set$c = b$ and recompute noise RSS
The candidate with the lowest total weighted RSS wins. Ties keep the lower < on RSS).
Second pass. If knot_x becomes knot_x stays the discrete winner.
The search is exhaustive over those candidates. It is not a continuous breakpoint estimator, and it is not "globally optimal" over all possible real-valued splits.
lod(std_mult=2):
- If
$a \le 0$ , return$\infty$ . - Intersection
$x_{\mathrm{int}} = (c-b)/a$ . - Noise observations:
$y$ with$x < x_{\mathrm{int}}$ . If there are fewer thanmin_noise_points(default 2) such observations, return$\infty$ . -
$\sigma$ isnp.std(noise_y, ddof=1). -
$\mathrm{LOD} = (c + \mathrm{std_mult}\cdot\sigma - b) / a$ . - If LOD is non-finite or
LOD > max(x), return$\infty$ . - If the number of unique
$x$ values strictly above LOD is less thanmin_linear_points(default 1), return$\infty$ .
min_noise_points counts observations. min_linear_points counts unique concentrations.
loq() and loq(method="bootstrap") (default method):
- If LOD is infinite, LOQ is infinite.
- Build a grid
np.linspace(LOD, max(x), grid_points)withgrid_points=100. - Nonparametric bootstrap of observation triples
$(x,y,W)$ ,n_boot_reps=100,seed=42. Each replicate refits the CF knot search. CV at a grid point isnanstd(..., ddof=1) / nanmeanof the bootstrap predictions. -
find_loq_thresholdon that grid: first positive grid$x$ wherecv <= cv_threshforsliding_windowconsecutive grid points (cv_thresh=0.20,window=3). Window is capped at the number of positive-grid points.window < 1yields$\infty$ . - If that value is non-finite,
$\le 0$ , or$\ge \max(x)$ , return$\infty$ .
The three-point window is consecutive grid points, not consecutive calibration levels.
If the float64 replicate matrix would exceed 100 MB, the vectorized bootstrap emits ResourceWarning and falls back to a per-replicate loop. Both paths draw indices from SeedSequence(seed).spawn(n_reps).
summary()["loq"] calls loq() and is therefore bootstrap.
loq(method="delta") and loq_delta() share one path. They never call bootstrap.
Linear-segment residuals use covariance() is then None). Prediction variance at
CV is 2 * min_spacing around UserWarning is emitted and the value is still computed.
Same find_loq_threshold rule as bootstrap (<=, window from sliding_window).
I leave bootstrap as the default. Delta is a different estimator. I will not pretend a faster number is the same number.
loqculate fit ... --fast is CF-only. It calls loq(method="delta") first; if that LOQ is infinite, it calls loq(method="bootstrap") once. Other models exit with an error. The Python methods above do not do that fallback.
n_boot_reps=100, seed=42, min_noise_points=2, min_linear_points=1, sliding_window=3, grid_points=100.
loqculate v0.4.1 | Home | Getting started | CLI reference | Troubleshooting | Changelog | MIT License
loqculate Wiki
Start
Models
Use loqculate
Solve a problem
Contribute