Changelog
Source:NEWS.md
xplus 1.1.1
- Seeded functions (
xplus(),xplus_elkan_noto(),xplus_naive(),pu_mask(),simulate_pu_data()) now restore the caller’s RNG state on exit instead of clobbering.Random.seed. - New pkgdown article “Seeing PU learning in two dimensions” visualizing linear and nonlinear PU problems with glmnet and ranger probability surfaces.
xplus 1.1.0
- New PU baselines
xplus_elkan_noto()andxplus_naive()expressed on the same backend contract asxplus(), enabling honest head-to-head comparisons: Elkan-Noto rescales P-vs-U probabilities by the estimated labeling propensity (mean or median over labeled positives), and the naive baseline treats all unlabeled instances as negatives. Both returnxplus_baselineobjects withpredictsupport and a$cutoff. -
pu_xplus()registers xplus as a parsnip model (engine"xplus", classification mode) sofit_xy()/fit(),predict(type = "prob"),update(), andtune::tune_grid()/finetune::tune_sim_anneal()all work against the backend contract. Registration is automatic on load when parsnip is installed and is idempotent. Thebackendargument selects the learner; backend-constructor arguments (trees,learn_rate,mtry,min_n,tree_depth,sample_size,loss_reduction) accepttune()placeholders withdialsparameter mappings and are ignored with a warning when the selected backend does not accept them. Standardyardstickmetrics over observed labels give the PU-valid positive-vs-unlabeled score for free. - Pluggable fitting backends:
xplus()gains abackendargument accepting"glmnet"(default, historical behavior),"ranger","gam", or a customxplus_backend()spec withfit/predictfunctions.alphaandcv_measureconfigure the glmnet backend only; non-CV backends record"none"inhistory$cv_measure. - New backend constructors
xplus_backend_glmnet(),xplus_backend_ranger(),xplus_backend_gam(),xplus_backend_xgboost(), andxplus_backend_lightgbm();ranger,mgcv,xgboost, andlightgbmmove toSuggests. Boosting backends report out-of-foldfit_predictscores fromxgb.cv/lgb.cvon the xplus CV folds, the honest analogue of ranger’s out-of-bag predictions. - New
xplus_backend_parsnip()adapter wrapping anyparsnipmodel spec (e.g.rand_forest() |> set_engine("ranger")) as anxplus()backend: the spec’s mode flips between classification (binary iterative targets) and regression (fractional final targets), case weights map tohardhat::frequency_weights()/importance_weights(), engine seeds are injected for reproducibility, andfit_predictreuses ranger out-of-bag scores when the engine stores them.parsnip,hardhat, andrlangmove toSuggests. - Backend capability flags
supports_fractionalandsupports_weightsonxplus_backend(): fractional-incompatible learners fail with a clear error when the final pseudo-label targets are soft, and weight-ignoring learners warn once undersampling = "bootstrap". Both default toTRUE, preserving the existing contract. - New
pu_score()andxplus_grid()for learner selection without negative labels: the PU-valid score is the positive-vs-unlabeled AUC of the honest stored predictions, which ranks learners consistently under SCAR.xplus_grid()compares backend names/specs or evaluates a constructor over aparamsdata-frame grid on shared seeds, returning a ranked leaderboard with per-candidate errors captured. -
simulate_pu_data()gains"xor"(checkerboard sign interactions) and"mixture"(multimodal positive clusters) boundaries, and newpu_mask()converts any open binary dataset into PU labels under SCAR — used byinst/benchmarks/realdataon UCI spambase and mushroom. - New
get_importance()returning backend feature scores (elastic-net coefficients for glmnet, variable importance for ranger, smooth-term significance for gam).coef()remains glmnet-only. - New
simulate_pu_data()synthetic PU generator with linear, interaction and nonlinear boundaries under SCAR labeling for benchmark experiments. -
predict()accepts non-glmnet backends;sstays glmnet-specific.summary()/print()report the backend;predicted_coefficientsis a sparse zero column for backends without coefficients. - Backends may declare
fit_predict(model, x)for honest (out-of-bag or held-out-fold) predictions on their fitted rows;xplus()uses them after the final fit for the stored predictions and classification cutoff, with non-finite entries falling back topredict. The ranger backend implements it via ranger’s out-of-bag predictions, fixing a cutoff calibrated on memorized in-sample scores that no prediction could reach (F1 collapsed to zero on hidden positives).predict()withoutnewxreturns the stored honest training predictions on non-glmnet backends.
xplus 1.0.2
CRAN release: 2026-09-26
- Resubmission to CRAN. Fixed the reviewer notes from Konstanze Lauseker: removed
\examplesfrom the unexported internal functionsnew_xplus()andvalidate_xplus(); the package no longer uses\dontrun{}anywhere; andxplus()no longer reads or writes.GlobalEnvdirectly (the optionalseedargument uses a plainset.seed()call).
xplus 1.0.1
- Resubmission to CRAN. Fixed NOTEs reported in the incoming pre-test: reworded
Descriptionto avoid false-positive spelling flags and removed the private development repository URL fromNEWS.mdandREADME.md.
xplus 1.0.0
This is a major, breaking upgrade of the PLUS-derived package extensions, not an exact reproduction of the paper or evidence of predictive superiority. Response-scale model scores are not guaranteed to be calibrated probabilities. The package remains xplus; the production repository is https://github.com/alrobles/xplus. Development, audit harnesses and historical baselines live in a separate development repository.
Breaking interfaces and metrics
- Require R >= 4.1.0 for native-pipe syntax and declare glmnet >= 4.1-8. Verification uses R 4.5.2 / glmnet 5.0; other supported versions have not thereby been verified.
- Reject
learning_rate = 0; the accepted interval is(0, 1]. - Interpret binary factors by labels, not level codes. Single-lambda class predictions now have fixed factor levels
"0","1"; multiple lambdas retain a 0/1 matrix. Classification uses a strict> object$cutoffcomparison. - Accept positional
newxinpredict(). Validate finite numeric features; named training features require an exact set of nonempty unique prediction names and are automatically aligned. Reject mismatches and unsupported dots. - Respect
sfor training and new-data prediction, including numeric lambdas. Cache-only objects support only"lambda.min"without new data.get_auc()forwards prediction arguments and requires one lambda;assess()can return per-lambda metrics. - Require finite binary truth, or finite nonnegative two-column negative/positive masses for soft truth or counts (
assess()/auc_matrix()). Soft vectors are not binary truth. Weights must be finite, nonnegative and row-aligned, without recycling. Invalid rows are errors, not silently dropped observations. - Undefined AUC returns
NAwith a warning when either effective class mass is zero. Zero effective total mass/weight makes assessment undefined. Ties receive half credit; constant scores with both classes have AUC 0.5. - MSE and MAE retain the two-class-column loss convention: twice scalar binary loss. Class-mass totals contribute to effective row weights. Deviance clips probabilities to
[1e-5, 1 - 1e-5]; other metrics do not inherit that clipping.
Sampling, CV and stopping
- Default
sampling = "bootstrap"preserves replacement multiplicities as case weights on unique rows. Duplicate identities never cross CV folds.sampling = "unique"retains legacy deduplication, not all legacy behavior. -
sample_use_timeis a budget of completed inclusion rounds per identity, not bootstrap draws. Record bothsampling_countsanddraw_counts. - Default
cv_measure = "deviance"in both iterative and final fitting stages. AUC remains opt-in, with an explicit warning and deviance fallback for fewer than 10 observations per fold on average; iterative effective measures appear inhistory. - Require at least three positive and three unlabeled input observations. Reduce requested folds to available class counts; require three unique members of each iterative training class and retry degenerate samples at most 20 times before reporting
stop_reason = "degenerate_labels". - Preserve the selected global-update, hard-thresholded iterative training path when
learning_rate < 1;learning_rate = 1uses sampled Bernoulli updates. Final targets remain soft in both paths. Reference sampling budgets and smoothing should not be mistaken for newly invented package extensions. - Expose
sigmoid_scale = 10separately from glmnet elastic-netalpha. - Default
min_iter = 5,stability_window = 5,min_coverage = 0.9. Stability compares undamped mapped scores against previous pseudo-labels over all unlabeled cases. A full window of consecutive scores strictly aboveconvergence_thresholdand minimum coverage are required; damping alone cannot create convergence. Recordmax_iter,budget_exhausted,degenerate_labelsandlabel_stabilitydistinctly rather than implying every stop is success.
Final fitting and reproducibility
- Validate effective class mass on the full final dataset and every CV training split (mean positive proportion strictly within
1e-5and1 - 1e-5). Soft labels all above 0.5 remain valid when mass is sufficient; hard-class counts do not trigger final fallback. - Warn when reverting to original PU labels and record
fallback_usedandfallback_reason. Preserveoriginal_y, proposedpseudo_labels, actualfinal_labels/y, iterationhistory, sampling/draw counts andfinal_foldid. Insufficient original-label mass is an error, not a hidden recovery. - Isolate an explicit
seedfrom the caller’s RNG stream and restore its prior state, including when no.Random.seedexisted.
Documentation and verification
- Regenerate reference manuals from current roxygen contracts. Installation examples target
alrobles/xpluswithout embedded credentials. - Diagnostic harnesses, the historical numerical-audit baseline and candidate diagnostics are maintained in a separate development repository; they are not part of the production source tree.
- Document
Rscript -e 'devtools::test(stop_on_failure = TRUE)'and require inspection of FAIL/WARN/SKIP counts. Keep build/check output outside the tracked checkout.
xplus 0.1.1
- Fixed a crash when the pseudo-labels of the iterative training subset collapse to a single class: fitting now stops cleanly with
stop_reason = "degenerate_labels"instead of failing insideglmnet::cv.glmnet(). - Sampling probabilities are now clamped at zero when the unlabeled-sampling budget is decremented, and sampling is skipped once the budget is fully exhausted (avoids an uninformative
sample()error).
xplus 0.1.0
- Initial release.
- Implements the PLUS algorithm for positive-unlabeled learning (Zhou et al., 2022, doi:10.1371/journal.pcbi.1009956).
- Provides
xplus()fitting function with iterative pseudo-label updates. - S3 methods:
predict(),coef(),summary(),print(),assess(),get_auc(), andget_predictions(). - Ships bundled datasets:
lacs,lacsSample, andbinexample.