Make model = "best" consistent across entry points - #232
Conversation
'best' was only implemented inside GeoLift(); every other entry point passed the raw string into augsynth's progfunc: - the five simulation-based functions (GeoLiftPowerFinder, GeoLiftPower.search, NumberLocations, GeoLiftPower, GeoLiftMarketSelection) died with "progfunc must be one of ..." buried inside a foreach worker; - GetWeights() documents 'best' but died on the same validation; - inside GeoLift() itself, candidate failures in the 'best' trial were silently swallowed (tryCatch -> scored as L2 = 1, a sentinel a fitted candidate can lose to since Scaled L2 can exceed 1), so with current CRAN gsynth (>= 1.3.0) the GSYN candidate never fits and nobody is told (upstream augsynth defect, reported separately). Changes: - extract the 'best' trial into an internal ResolveBestModel() helper (@nord) that implements the documented rule directly: lowest Scaled L2 Imbalance among the candidates that actually fitted, ties going to the simpler model (none, then ridge, then GSYN). The old strict- comparison chain could return a candidate that had FAILED (or one strictly worse than a tied pair) whenever the other two tied. A failed candidate — error, or a scaled_l2_imbalance that is not a single finite number (NaN/NULL) — is reported via message() with the underlying error and scored Inf; if every candidate fails the selection stops with a clear error instead of silently returning 'none'. The single-treatment-location GSYN skip is announced; - wire GetWeights(model = 'best') to the same helper, making the documented value actually work; - add an early, self-explanatory stop() for model = 'best' in the five simulation entry points (they fit one outcome model at a time by design; MultiCellMarketSelection inherits the clear error); - docs: remove the 'best' row from ASCMExecution() (pass-through, never implemented there); fix the \item{"best:} quote typo in 4 blocks.
man/ regenerated with roxygen2, keeping only content changes (quote typo fix, ASCMExecution 'best' row removal); testthat added to Suggests for the new test suite.
Unit tests of ResolveBestModel() with ASCMExecution mocked: plain minimum, failed candidates never selected (even on ties among the fitted ones), tie-breaking toward the simpler model, NaN/NULL imbalances treated as failures, all-candidates-failed error, and the single-location GSYN skip. End-to-end: the new clear error in the simulation entry points, GetWeights(model = 'best') returning weights, the announced GSYN skip, and an unchanged GeoLift(model = 'ridge') fit as a regression guard.
|
Hi @takechanman1228! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks! |
|
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks! |
Addresses the mechanical parts of #231; the selection-criterion question raised there stays open.
model = "best"is only implemented insideGeoLift(). The other entry points pass the string straight into augsynth'sprogfunc: the simulation functions die with an unhelpful error inside a foreach worker, andGetWeights()documents"best"but errors the same way. InsideGeoLift(), a failed candidate is silently scored L2 = 1, which a real fit can lose to (scaled L2 can exceed 1).ResolveBestModel()helper that picks the lowest scaled L2 among the candidates that actually fitted, ties going to the simpler model. Failed candidates (error, or a non-finite imbalance) are excluded with amessage(); if every candidate fails it stops. The previous comparison chain could return a failed candidate when the other two tied.GetWeights(model = "best")now works as documented, via the same helper.model = "best"in the five simulation entry points (it was never a documented value there)."best"from theASCMExecution()docs (never implemented there) and fixed the\item{"best:}typo; regenerated the affected man pages.ASCMExecutionmocked, plus end-to-end checks (slow ones areskip_on_cran()).Note: even with the GSYN fit repaired upstream (ebenmichael/augsynth#119), GSYN cannot currently win the comparison — for no-covariate runs augsynth reports the same scaled L2 for "none" and "GSYN" (details in #231). This PR only fixes the mechanics; what "best" should select on is #231 's open question.