mescla.mixing.ml.mix_ml¶
- mescla.mixing.ml.mix_ml(endmembers, samples, sd_endmembers=None, sd_samples=None, n_starts=10, max_iter=2000, screen_iter=30, tol=1e-09, ratio_tol=1e-07, seed=0)[source]¶
Estimate mixing ratios and end-member concentrations jointly (MIX).
- Parameters:
endmembers (EndMembers, DataFrame or array, shape (ne, ns)) – Measured end-member compositions.
samples (WaterChemistry, DataFrame or array, shape (np, ns)) – Measured mixture compositions.
sd_endmembers (array_like, optional) – Standard deviations of the end-member analyses, shape
(ne, ns)or one value per species. Falls back to thesigmacarried byendmembers. These are usually the large ones: they must express spatial and temporal variability and conceptual error, not laboratory precision.sd_samples (array_like, optional) – Standard deviations of the sample analyses, shape
(np, ns)or one per species. Falls back to thesigmacarried bysamples.n_starts (int, default 10) – Random restarts, in addition to the least-squares and uniform starts. The paper reports convergence to different minima from different starting points and recommends exactly this: try least squares, uniform, and about ten random perturbations, then keep the best.
max_iter (int, default 2000) – Iteration cap for the final, fully converged run.
screen_iter (int, default 30) – Cheap budget used to rank the starting points before committing to one.
tol (float, default 1e-9) – Relative change in the objective at which to stop.
ratio_tol (float, default 1e-7) – Largest change in any mixing ratio at which to stop. Both this and
tolmust be satisfied.seed (int, optional)
- Returns:
MixingResult –
result.endmembersholds the revised compositions – compare them with what you measured.result.diagnostics["improvement_index"]quantifies how much they moved relative to their assigned uncertainty.- Return type:
Notes
The alternation has a long, very flat tail: the objective can keep creeping in the sixth decimal for thousands of iterations after the mixing ratios have settled to better than 1e-4, which is already far beyond analytical precision.
convergedtherefore reports whether both movement criteria were met, anddiagnostics["final_ratio_change"]tells you how much the ratios were still moving when it stopped – read that rather than the flag alone.Assigning the standard deviations is a modelling decision, not a formality, and it is the step that decides your answer. The asymmetry matters more than the absolute values: make the end-member sigmas larger than the sample sigmas when you want the mixtures to reshape the end-members, and smaller when you have already established the end-members and want them preserved. Always sweep them (
mescla.uncertainty.identifiability.sigma_sweep()) and report the sweep.Examples
>>> result = mix_ml(endmembers, samples, ... sd_endmembers=0.30 * endmembers.data, ... sd_samples=0.05 * samples.data) >>> result.endmembers.to_frame() # revised compositions