<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>Imad El Badisy</title>
<link>https://elbadisyimad.com/</link>
<atom:link href="https://elbadisyimad.com/index.xml" rel="self" type="application/rss+xml"/>
<description>Imad El Badisy, PhD. Health data scientist and computational methodologist building software for machine learning and computational biostatistics.</description>
<image>
<url>https://elbadisyimad.com/profile.jpg</url>
<title>Imad El Badisy</title>
<link>https://elbadisyimad.com/</link>
</image>
<generator>quarto-1.8.24</generator>
<lastBuildDate>Sun, 04 Oct 2026 23:00:00 GMT</lastBuildDate>
<item>
  <title>Hazards, p-values and hybrid models: notes from ISCB GMDS 2026</title>
  <dc:creator>Imad El Badisy</dc:creator>
  <link>https://elbadisyimad.com/blog/2026-10-05-iscb-gmds-2026/</link>
  <description><![CDATA[ 





<section id="from-casablanca-to-freiburg" class="level2">
<h2 class="anchored" data-anchor-id="from-casablanca-to-freiburg">From Casablanca to Freiburg</h2>
<p>I flew from Casablanca to Frankfurt, walked from the terminal to the airport’s long-distance train station, and took the ICE south to Freiburg im Breisgau: about two hours along the Rhine valley, with the Black Forest rising on the left. Strangely, after spending almost a third of my life in France, this was my first time in Germany. I had heard about German train delays and did not quite believe it. Both my trains changed times, and the return was the more stressful one.</p>
<p>The conference theme was <strong>“BIG DATA, small data, Your Data: Transitions in the age of biomedical AI”</strong>. Over four days, one idea kept coming back to me, and it had less to do with methods than with where data comes from. I start there.</p>
</section>
<section id="health-data-as-national-infrastructure" class="level2">
<h2 class="anchored" data-anchor-id="health-data-as-national-infrastructure">Health data as national infrastructure</h2>
<p>Cathie Sudlow’s opening keynote, <em>Future of Population Health Research: a UK Health Data Perspective</em>, described how the UK linked national health datasets and built secure data environments covering the whole population of England. Her underlying message: health data is any data relevant to our health, and it should be treated as <strong>shared national infrastructure</strong> with common sharing principles, not as a pile of separate project datasets.</p>
<p>I kept translating this to Morocco. Our data is fragmented across hospitals, national programmes and research teams, with no common layer connecting them. A Moroccan initiative in the spirit of Health Data Research UK, would be a major opportunity: researchers contributing data under shared principles, a common access framework, and eventually an agent layer that lets people query that data in natural language. None of this works without well-curated data, which is a practical problem I want to help solve.</p>
</section>
<section id="my-poster-interpretability-as-an-estimand" class="level2">
<h2 class="anchored" data-anchor-id="my-poster-interpretability-as-an-estimand">My poster: interpretability as an estimand</h2>
<p>I presented <em>A Framework for Assessing Imputation Methods for Survival Prediction Models via Interpretability Distortion</em> (with Roch Giorgi). The starting point: when a model is used to understand the outcome-covariate relationship, its interpretability summaries (partial dependence, time-dependent SHAP, permutation importance, calibration and Brier curves) are quantities we estimate, so they should be treated as <strong>estimands</strong>. That makes it possible to measure how much imputation distorts them relative to a complete-data reference, for machine learning models and not only for regression coefficients. In our benchmark, some methods preserved variable rankings while altering effect sizes: good prediction did not guarantee a stable interpretation.</p>
<p>The rest of this post covers the talks that stayed with me.</p>
</section>
<section id="are-hazard-ratios-really-hazardous" class="level2">
<h2 class="anchored" data-anchor-id="are-hazard-ratios-really-hazardous">Are hazard ratios really hazardous?</h2>
<p>Hernán’s 2010 commentary <em>The hazards of hazard ratios</em> argued that Cox hazard ratios carry a built-in selection bias: a hazard ratio that declines over follow-up may only reflect latent frailty, not a waning treatment effect. Many people have been uneasy about Cox regression since.</p>
<p>In the STRATOS symposium, Michal Abrahamowicz (<em>How important are the Hazards of Hazard Ratios?</em>) revisited the argument with extensive simulations. The selection bias turns out to be modest unless unmeasured frailty has a very strong effect. In simulations mimicking the trial Hernán discussed, an unmeasured risk factor alone could practically not reproduce the observed decline in the hazard ratio. Declining adherence and biological changes under prolonged treatment are more plausible explanations. Their conclusion: the concern is largely overstated.</p>
<p>This matters for anyone working on time-varying effects, as I do. A time-varying hazard ratio is often a real signal worth modelling, not an artefact to explain away. It also made me want to look again at alternatives to the classical proportional hazards test, and at reporting several models rather than one.</p>
</section>
<section id="what-are-p-values-good-for" class="level2">
<h2 class="anchored" data-anchor-id="what-are-p-values-good-for">What are p-values good for?</h2>
<p>In the same session, James Carpenter (<em>P-values and hypothesis testing: beyond polemics to practical solutions</em>) moved past the debate that has run since the 2019 <em>Nature</em> call to retire statistical significance. <strong>P-values are often used to justify a result rather than answer a question</strong>, and on their own they are not reproducible. As an attendee pointed out, neither are confidence intervals. The useful part was organising good practice around the goal of the analysis (description, prediction or causal explanation), supported by registration, initial data analysis and transparent reporting.</p>
<p>The point I liked most: in model building, a p-value can be a legitimate <strong>tuning parameter</strong>, for example as a selection threshold. Used that way it is a knob in an algorithm, not a claim about truth, and I think that distinction deserves more attention.</p>
</section>
<section id="how-much-nonlinearity-should-a-model-be-allowed" class="level2">
<h2 class="anchored" data-anchor-id="how-much-nonlinearity-should-a-model-be-allowed">How much nonlinearity should a model be allowed?</h2>
<p>My favourite methods talk was Tom Splittgerber’s <em>LiD-GLM: Lipschitz-constrained Deep Generalized Linear Models</em> (with Marvin N. Wright, Niklas Koenen and Werner Brannath). The model passes covariates through an invertible residual neural network before a GLM, and hard-constrains the network’s <strong>Lipschitz constant</strong>. That constant becomes an explicit dial between “this is just the GLM” and “this is a free neural network”. The model is initialised from a fitted GLM, so if nonlinearity adds nothing, you simply get the GLM back. In the summary slide’s words, the Lipschitz constant quantifies the compromise between expressiveness and interpretability, and tells you whether your problem needs complex ML at all.</p>
<p>In the same spirit, Ester Rosa’s poster on <em>Interpretable Kolmogorov-Arnold Networks via Penalized Splines for Clinical Prediction Modeling</em> showed KANs entering clinical prediction. KANs with spline edges sit naturally between additive models and neural networks, which is the space I am working in now for survival analysis.</p>
</section>
<section id="can-explanations-inherit-bias" class="level2">
<h2 class="anchored" data-anchor-id="can-explanations-inherit-bias">Can explanations inherit bias?</h2>
<p>A thread that ran through several sessions: <strong>SHAP values explain the model, not the data-generating process</strong>, so they can carry over confounding. When predictors are correlated or causally ordered, standard Shapley attributions can mislead. Asymmetric Shapley values, which respect a causal ordering (for example genetics before clinical variables), are one principled answer.</p>
<p>It left me thinking about variable importance for meaningful <em>groups</em> of variables (genomic, clinical, epidemiological) rather than single features.</p>
</section>
<section id="do-our-metrics-behave-badly" class="level2">
<h2 class="anchored" data-anchor-id="do-our-metrics-behave-badly">Do our metrics behave badly?</h2>
<p>Three talks fit together well. In the fairness session, Gary Collins (<em>A Fractured Landscape: Evaluating Fairness in Clinical Prediction Models</em>) pointed out that the c-statistic and calibration slope are non-collapsible, so an apparent subgroup “unfairness” can simply reflect case mix. Junfeng Wang showed that population-level net benefit can favour adopting a model even when overall utility does not improve. At STRATOS, Ben Van Calster scored 32 performance measures on properness and focus: only 17 pass both, and F1 fails both. His minimal reporting set is AUROC, a calibration plot, net benefit with a decision curve, and the distribution of predicted risks.</p>
<p>My takeaway: we spend a lot of effort building models and much less checking whether our metrics measure what we think. Fairness at the level of the individual, not only of groups, seems underexplored.</p>
</section>
<section id="causal-inference-for-survival-outcomes" class="level2">
<h2 class="anchored" data-anchor-id="causal-inference-for-survival-outcomes">Causal inference for survival outcomes</h2>
<p>Causal survival analysis still has real gaps. Two talks (at least was I was able to attend) approached them from very different angles: Yuan Liu’s two-step approach for survival outcomes under time-varying latent confounding, and Xinyuan Song’s conditional GANs for individualized causal mediation with survival outcomes. Both made me think about estimands. Hazard contrasts are hard to read causally, whereas restricted mean survival time is collapsible and easy to explain to clinicians. I would like to explore more causal survival work built on that kind of estimand, combined with flexible machine learning.</p>
</section>
<section id="other-things-i-noted" class="level2">
<h2 class="anchored" data-anchor-id="other-things-i-noted">Other things I noted</h2>
<ul>
<li><strong>Sample size for ML.</strong> The <em>pmsims</em> R package (Olaniran, Carr and colleagues) estimates sample size by simulation with an <em>assurance</em> criterion: hitting target performance with high probability, not only on average. A natural framework to extend to survival models.</li>
<li><strong>Conformal prediction is not calibration.</strong> Giulia Zamagni showed that models with very different calibration can give similar conformal coverage and interval widths. Report both.</li>
<li><strong>Calibration with censoring.</strong> David van Klaveren’s LOESS for censored data gives calibration curves that hold up when censoring depends on predicted risk.</li>
<li><strong>Missing data in bioequivalence.</strong> Jakob Winkler simulated how missing PK sampling times affect AUC, Cmax and bioequivalence conclusions in 2x2 crossover trials: a small, concrete and important problem.</li>
<li><strong>Spline choices.</strong> My recurring question in spline talks: were the degrees of freedom and knot placement tuned? They shape the curve as much as the method does.</li>
<li><strong>Statistical analysis plans.</strong> Marianne Huebner’s SAPI checklist made me wonder why ML projects almost never have a statistical analysis plan?</li>
</ul>
</section>
<section id="two-impressions" class="level2">
<h2 class="anchored" data-anchor-id="two-impressions">Two impressions</h2>
<p>Some of my best discussions happened at posters, and several deserved an oral slot, perhaps more than a few talks that felt less prepared. One example: Kerstin Rubarth and colleagues (FeMaR project) are replacing Germany’s 1986 rule-based pregnancy risk system with models trained on more than 110,000 pregnancies, with prospective validation under way. Very relevant to maternal health work in Morocco and great collaboration opportunity.</p>
<p>Talks on agentic AI, and agentic data science in particular, felt classic, even dated. The field moves faster than a submission cycle, and presenters likely stuck to abstracts written months earlier. Having built agentic data science tools myself, I expected the questions that matter now: how to evaluate an agent’s analysis against a known truth, how to keep every step reproducible and auditable, and how to control false positives when an agent iterates over analyses until something looks good. That last one is a classic multiplicity problem, and statisticians are well placed to solve it.</p>
</section>
<section id="coming-home" class="level2">
<h2 class="anchored" data-anchor-id="coming-home">Coming home</h2>
<p>I came for survival methods and machine learning, and I got plenty of both. What I kept thinking about on the train back to Frankfurt, though, was Sudlow’s keynote: good methods need data that exists, is connected, and can be trusted. Building that in Morocco is the part I most want to work on next.</p>
<p>Thanks to the organisers for this great management, in particular conference presidents Nadine Binder and Harald Binder, and to the ISCB and GMDS teams for an excellent week in Freiburg.</p>
<hr>
</section>
<section id="talks-mentioned" class="level2">
<h2 class="anchored" data-anchor-id="talks-mentioned">Talks mentioned</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Talk</th>
<th>Speaker (authors)</th>
<th>When and where</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Future of Population Health Research: a UK Health Data Perspective (keynote)</td>
<td>Cathie Sudlow</td>
<td>Mon 28.09, 09:45-10:30, Rolf Böhme Saal</td>
</tr>
<tr class="even">
<td>A Framework for Assessing Imputation Methods for Survival Prediction Models via Interpretability Distortion (poster 28-P2-12)</td>
<td>Imad El Badisy (with Roch Giorgi)</td>
<td>Mon 28.09, poster session P2</td>
</tr>
<tr class="odd">
<td>Simulating the effect of imputing missing pharmacokinetic sampling time points on bioequivalence assessment in typical early phase clinical trials</td>
<td>Jakob Winkler (with Markus Waser)</td>
<td>Mon 28.09, 12:00-12:15, Room N1</td>
</tr>
<tr class="even">
<td>A Flexible, Simulation-Based Approach to Sample Size Estimation for Prediction Modelling and Machine Learning: The pmsims R Package</td>
<td>Oyebayo Ridwan Olaniran, Ewan Carr (with Diana Shamsutdinova, Sarah Markham, Daniel Stahl, Gordon Forbes)</td>
<td>Mon 28.09, 13:45-14:00, Runder Saal</td>
</tr>
<tr class="odd">
<td>Locally Estimated Scatterplot Smoothing for Censored Survival Data</td>
<td>David van Klaveren (with Peter C. Austin, Patrick W. Serruys, Ben Van Calster, Frank E. Harrell Jr.)</td>
<td>Mon 28.09, 16:30-16:45, Runder Saal</td>
</tr>
<tr class="even">
<td>Conformal prediction under miscalibration: what coverage and interval width do not capture</td>
<td>Giulia Zamagni (with Giulia Barbati)</td>
<td>Tue 29.09, 11:45-12:00, Runder Saal</td>
</tr>
<tr class="odd">
<td>CGAN for individualized causal mediation analysis with survival outcome</td>
<td>Xinyuan Song (with Cheng Huan, Hongwei Yuan)</td>
<td>Tue 29.09, 12:00-12:30, Rolf Böhme Saal</td>
</tr>
<tr class="even">
<td>Interpretable Kolmogorov-Arnold Networks via Penalized Splines for Clinical Prediction Modeling (poster 29-P2-04)</td>
<td>Ester Rosa (with Stefania Lando, Gloria Brigiari, Dario Gregori)</td>
<td>Tue 29.09, poster session P2</td>
</tr>
<tr class="odd">
<td>A two-step causal inference approach for survival outcomes under time-varying latent confounding</td>
<td>Yuan Liu (with Marta Fiocco, Johannes H.M. Merks, Marta Spreafico)</td>
<td>Wed 30.09, 10:00-10:15, Room N1</td>
</tr>
<tr class="even">
<td>LiD-GLM: Lipschitz-constrained Deep Generalized Linear Models</td>
<td>Tom Splittgerber (with Marvin N. Wright, Niklas Koenen, Werner Brannath)</td>
<td>Wed 30.09, 11:00-11:15, Room K2</td>
</tr>
<tr class="odd">
<td>A Fractured Landscape: Evaluating Fairness in Clinical Prediction Models</td>
<td>Gary Collins</td>
<td>Wed 30.09, 14:00-14:30, Rolf Böhme Saal</td>
</tr>
<tr class="even">
<td>When Net Benefit Misleads the Decision: A Cautionary Note on Population-Level Decision Curve Analysis in the Presence of Subgroups</td>
<td>Junfeng Wang (with Kim Zhipei Wang, Ben Van Calster, Nan van Geloven, Ewout Steyerberg, Laure Wynants)</td>
<td>Wed 30.09, 14:30-15:00, Rolf Böhme Saal</td>
</tr>
<tr class="odd">
<td>Beyond Rule-Based Risk Assessment: Data-Driven Prediction of Pregnancy and Birth Complications in the FeMaR Project (poster 30-P2-05)</td>
<td>Kerstin Rubarth and colleagues</td>
<td>Wed 30.09, poster session P2</td>
</tr>
<tr class="even">
<td>P-values and hypothesis testing: beyond polemics to practical solutions</td>
<td>James Carpenter</td>
<td>Thu 01.10, 09:10-09:35, Runder Saal (STRATOS)</td>
</tr>
<tr class="odd">
<td>How important are the Hazards of Hazard Ratios?</td>
<td>Michal Abrahamowicz (with Marie-Eve Beauchamp, Emily Roberts, Jeremy Taylor)</td>
<td>Thu 01.10, 09:35-10:00, Runder Saal (STRATOS)</td>
</tr>
<tr class="even">
<td>Statistical analysis plan with initial data analysis (SAPI): Validating the SAPI checklist in analysis projects</td>
<td>Marianne Huebner</td>
<td>Thu 01.10, 11:00-11:25, Runder Saal (STRATOS)</td>
</tr>
<tr class="odd">
<td>Performance evaluation of predictive AI models to support medical decisions: overview and guidance</td>
<td>Ben Van Calster (with Ewout Steyerberg)</td>
<td>Thu 01.10, 14:27-14:44, STRATOS</td>
</tr>
</tbody>
</table>


</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>conferences</category>
  <category>biostatistics</category>
  <category>survival-analysis</category>
  <category>machine-learning</category>
  <category>causal-inference</category>
  <guid>https://elbadisyimad.com/blog/2026-10-05-iscb-gmds-2026/</guid>
  <pubDate>Sun, 04 Oct 2026 23:00:00 GMT</pubDate>
</item>
<item>
  <title>basetable: A Tutorial</title>
  <dc:creator>Imad El Badisy</dc:creator>
  <link>https://elbadisyimad.com/blog/2026-09-05-basetable-tutorial/</link>
  <description><![CDATA[ <p><code>basetable</code> is a fast, dependency-free data-manipulation package for R that keeps the base-R interface people already know. This post walks through the package: what it is, how to install it, and worked examples for the handful of functions that carry most of the day-to-day work - <code><a href="https://rdrr.io/r/base/subset.html">subset()</a></code>, <code><a href="https://rdrr.io/r/base/transform.html">transform()</a></code>, <code><a href="https://rdrr.io/r/stats/aggregate.html">aggregate()</a></code>, <code><a href="https://rdrr.io/r/base/merge.html">merge()</a></code> / <code>semimerge()</code>, and <code>describe()</code> - followed by how it stacks up against <code>data.table</code> and <code>dplyr</code> on speed and memory.</p>
<section id="basetable" class="level1"><h1>basetable</h1>
<!-- badges: start -->
<p><a href="https://github.com/ielbadisy/basetable/actions/workflows/R-CMD-check.yaml"><img src="https://github.com/ielbadisy/basetable/actions/workflows/R-CMD-check.yaml/badge.svg" class="img-fluid" alt="R-CMD-check"></a> <a href="https://lifecycle.r-lib.org/articles/stages.html#stable"><img src="https://img.shields.io/badge/lifecycle-stable-brightgreen.svg" class="img-fluid" alt="Lifecycle: stable"></a> <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" class="img-fluid" alt="License: MIT"></a> <!-- badges: end --></p>
<p><code>basetable</code> is a fast in-memory data-manipulation package for R with a <strong>base-R interface</strong> and <strong>no dependencies</strong>. You write <code><a href="https://rdrr.io/r/base/subset.html">subset()</a></code>, <code><a href="https://rdrr.io/r/base/transform.html">transform()</a></code>, <code><a href="https://rdrr.io/r/stats/aggregate.html">aggregate()</a></code>, <code><a href="https://rdrr.io/r/base/merge.html">merge()</a></code>, <code><a href="https://rdrr.io/r/base/split.html">split()</a></code>, and the work runs on the package’s own C++ engine. There is no <code>data.table</code>, no <code>dplyr</code>, no Arrow underneath, and nothing in <code>Imports</code> beyond the base and recommended packages (<code>parallel</code>, <code>stats</code>, <code>utils</code>).</p>
<p>Every verb returns a <code>basetable</code>: an ordinary <code>data.frame</code> with one extra class so it prints compactly and <code>[</code> keeps the class. <code><a href="https://rdrr.io/r/base/as.data.frame.html">as.data.frame()</a></code> strips it back to a plain frame.</p>
<p>This is a deliberately focused tool. It is aimed at</p>
<ul>
<li>people <strong>teaching or learning base R</strong> who want speed without the cognitive load of tidy evaluation or <code>[i, j, by]</code>, and</li>
<li>codebases already built on <code><a href="https://rdrr.io/r/base/subset.html">subset()</a></code> / <code><a href="https://rdrr.io/r/base/merge.html">merge()</a></code> / <code><a href="https://rdrr.io/r/stats/aggregate.html">aggregate()</a></code> that want a faster engine <strong>without a rewrite</strong>.</li>
</ul>
<section id="design" class="level2"><h2 class="anchored" data-anchor-id="design">Design</h2>
<ul>
<li>
<strong>Base-style naming and semantics.</strong> Functions read like <code><a href="https://rdrr.io/r/base/subset.html">subset()</a></code>, <code><a href="https://rdrr.io/r/base/transform.html">transform()</a></code>, <code><a href="https://rdrr.io/r/stats/aggregate.html">aggregate()</a></code>, <code><a href="https://rdrr.io/r/base/merge.html">merge()</a></code>, <code><a href="https://rdrr.io/r/base/split.html">split()</a></code>.</li>
<li>
<strong>A native C++ engine.</strong> Projection, filtering, ordering, distinct, grouping, all join kinds, row-bind and <code><a href="https://rdrr.io/r/base/subset.html">subset()</a></code> predicate evaluation run in compiled <code>.Call</code> kernels. There is no third-party compute backend.</li>
<li>
<strong>Explicit, standard-evaluation interfaces.</strong> Column names are strings, not captured symbols (with the marked exceptions <code><a href="https://rdrr.io/r/base/subset.html">subset()</a></code> and <code><a href="https://rdrr.io/r/base/transform.html">transform()</a></code> inherit from base R).</li>
<li>
<strong>Zero hard dependencies.</strong> <code>data.table</code> and <code>dplyr</code> appear only in <code>Suggests</code>, and only as competitors in the benchmark vignette.</li>
</ul></section><section id="installation" class="level2"><h2 class="anchored" data-anchor-id="installation">Installation</h2>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/utils/install.packages.html">install.packages</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"basetable"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<p>Or the development version:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># install.packages("pak")</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pak</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://pak.r-lib.org/reference/pak.html">pak</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ielbadisy/basetable"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
</section><section id="minimal-examples" class="level2"><h2 class="anchored" data-anchor-id="minimal-examples">Minimal examples</h2>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># nested</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basetable</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/basetable/man/describe.html">describe</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span></span>
<span>  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basetable</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/basetable/man/subset.html">transform</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span></span>
<span>    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basetable</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/basetable/man/subset.html">subset</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mtcars</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cyl</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, select <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mpg"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"hp"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wt"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cyl"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>,</span>
<span>    power <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">hp</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">wt</span></span>
<span>  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># basetable: 5 x 14
  column   class n missing missing_prop distinct       mean         sd
1    mpg numeric 7       0            0        6  19.742857  1.4535670
2     hp numeric 7       0            0        4 122.285714 24.2604911
3     wt numeric 7       0            0        6   3.117143  0.3563455
4    cyl numeric 7       0            0        1   6.000000  0.0000000
5  power numeric 7       0            0        6  39.927938 10.8533912
        min       q25    median      q75      max top
1  17.80000  18.65000  19.70000  21.0000  21.4000    
2 105.00000 110.00000 110.00000 123.0000 175.0000    
3   2.62000   2.82250   3.21500   3.4400   3.4600    
4   6.00000   6.00000   6.00000   6.0000   6.0000    
5  30.34682  34.98522  35.75581  40.1228  63.1769    </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># pipe</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mtcars</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span>  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basetable</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/basetable/man/pick.html">pick</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mpg"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"hp"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wt"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cyl"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span>  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basetable</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/basetable/man/subset.html">transform</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>power <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">hp</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">wt</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span>  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basetable</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/basetable/man/aggregate.html">aggregate</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>by <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cyl"</span>, value <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mpg"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"power"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>, fun <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mean</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># basetable: 3 x 3
  cyl      mpg    power
1   4 26.66364 37.92533
2   6 19.74286 39.92794
3   8 15.10000 53.85964</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># table-1 style summary</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basetable</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/basetable/man/summarytab.html">summarytab</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span></span>
<span>  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basetable</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/basetable/man/subset.html">transform</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mtcars</span>, am <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/factor.html">factor</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">am</span>, labels <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Automatic"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Manual"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>,</span>
<span>  vars <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mpg"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"hp"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>, by <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"am"</span>, p_value <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span></span>
<span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># basetable: 2 x 6
  variable     level    Automatic       Manual      Overall p_value
1      mpg Mean (SD)   17.1 (3.8)   24.4 (6.2)   20.1 (6.0) 0.00137
2       hp Mean (SD) 160.3 (53.9) 126.8 (84.1) 146.7 (68.6)   0.221</code></pre>
</div>
</div>
<p>Every call above is qualified with <code>basetable::</code>, and for good reason: <code>basetable</code> intentionally reuses the base-R names <code><a href="https://rdrr.io/r/base/subset.html">subset()</a></code>, <code><a href="https://rdrr.io/r/base/transform.html">transform()</a></code>, <code><a href="https://rdrr.io/r/base/merge.html">merge()</a></code> and <code><a href="https://rdrr.io/r/base/split.html">split()</a></code>, so attaching it with a plain <code><a href="https://github.com/ielbadisy/basetable">library(basetable)</a></code> puts those ahead of <code>base</code> on the search path for the rest of the session - which can surprise other code, including tooling, that calls the base versions unqualified. Qualifying the calls, as described in “Using basetable alongside dplyr and data.table” below, avoids that entirely.</p>
</section><section id="tutorial" class="level2"><h2 class="anchored" data-anchor-id="tutorial">Tutorial</h2>
<p>The examples above are the pitch. The rest of this section is the short list of functions that carry most of the day-to-day work, one at a time.</p>
<section id="filtering-subset" class="level3"><h3 class="anchored" data-anchor-id="filtering-subset">Filtering: <code>subset()</code>
</h3>
<p>Same syntax as <code><a href="https://rdrr.io/r/base/subset.html">base::subset()</a></code> - a condition on the unquoted column names, plus an optional <code>select</code> - running on the C++ engine instead of R:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basetable</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/basetable/man/subset.html">subset</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mtcars</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cyl</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">hp</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, select <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mpg"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"hp"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wt"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cyl"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># basetable: 7 x 4
   mpg  hp    wt cyl
1 21.0 110 2.620   6
2 21.0 110 2.875   6
3 21.4 110 3.215   6
4 18.1 105 3.460   6
5 19.2 123 3.440   6
6 17.8 123 3.440   6
7 19.7 175 2.770   6</code></pre>
</div>
</div>
</section><section id="creating-columns-transform" class="level3"><h3 class="anchored" data-anchor-id="creating-columns-transform">Creating columns: <code>transform()</code>
</h3>
<p>Adds or overwrites columns from expressions on the existing ones, and later expressions in the same call can use columns created earlier in it:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mtcars</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span></span>
<span>  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basetable</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/basetable/man/subset.html">transform</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>power <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">hp</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">wt</span>, efficient <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mpg</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/mean.html">mean</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mpg</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># basetable: 32 x 13
    mpg cyl  disp  hp drat    wt  qsec vs am gear carb    power efficient
1  21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4 41.98473      TRUE
2  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4 38.26087      TRUE
3  22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1 40.08621      TRUE
4  21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1 34.21462      TRUE
5  18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2 50.87209     FALSE
6  18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1 30.34682     FALSE
7  14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4 68.62745     FALSE
8  24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2 19.43574      TRUE
9  22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2 30.15873      TRUE
10 19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4 35.75581     FALSE
# 22 more rows</code></pre>
</div>
</div>
</section><section id="grouped-summaries-aggregate" class="level3"><h3 class="anchored" data-anchor-id="grouped-summaries-aggregate">Grouped summaries: <code>aggregate()</code>
</h3>
<p>This is the one with the biggest gap in the benchmarks below - grouped reductions accumulate in compiled code without materialising intermediate columns, so a <code>sd</code> or a <code>count</code> by group allocates close to nothing:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basetable</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/basetable/man/aggregate.html">aggregate</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">airquality</span>, by <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Month"</span>, value <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ozone"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Temp"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>, fun <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mean</span>, na.rm <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># basetable: 5 x 3
  Month    Ozone     Temp
1     5 23.61538 65.54839
2     6 29.44444 79.10000
3     7 59.11538 83.90323
4     8 59.96154 83.96774
5     9 31.44828 76.90000</code></pre>
</div>
</div>
</section><section id="joins-merge-and-semimerge" class="level3"><h3 class="anchored" data-anchor-id="joins-merge-and-semimerge">Joins: <code>merge()</code> and <code>semimerge()</code>
</h3>
<p><code><a href="https://rdrr.io/r/base/merge.html">merge()</a></code> covers inner, left, right, and full joins through the same <code>all</code> / <code>all.x</code> / <code>all.y</code> arguments as <code><a href="https://rdrr.io/r/base/merge.html">base::merge()</a></code>, rows come back in input order rather than sorted by key. <code>semimerge()</code> filters one table by matches in another without adding columns - the join-as-filter case that a plain <code><a href="https://rdrr.io/r/base/merge.html">merge()</a></code> would otherwise need a follow-up <code><a href="https://rdrr.io/r/base/subset.html">subset()</a></code> for:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb15" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">left</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/data.frame.html">data.frame</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>id <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">letters</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">right</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/data.frame.html">data.frame</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>id <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>, y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">LETTERS</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basetable</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/basetable/man/merge.html">merge</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">left</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">right</span>, by <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"id"</span>, all.x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># basetable: 4 x 3
  id x    y
1  1 a &lt;NA&gt;
2  2 b    B
3  3 c    C
4  4 d &lt;NA&gt;</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb17" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basetable</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/basetable/man/semimerge.html">semimerge</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">left</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">right</span>, by <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"id"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># basetable: 2 x 2
  id x
1  2 b
2  3 c</code></pre>
</div>
</div>
</section><section id="exploration-describe-and-summarytab" class="level3"><h3 class="anchored" data-anchor-id="exploration-describe-and-summarytab">Exploration: <code>describe()</code> and <code>summarytab()</code>
</h3>
<p><code>describe()</code> is the quick per-column numeric summary; <code>summarytab()</code> builds a table-1-style comparison across a grouping variable, shown already in the minimal examples above with a p-value column:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb19" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basetable</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/basetable/man/describe.html">describe</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mtcars</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># basetable: 11 x 14
   column   class  n missing missing_prop distinct       mean          sd
1     mpg numeric 32       0            0       25  20.090625   6.0269481
2     cyl numeric 32       0            0        3   6.187500   1.7859216
3    disp numeric 32       0            0       27 230.721875 123.9386938
4      hp numeric 32       0            0       22 146.687500  68.5628685
5    drat numeric 32       0            0       22   3.596563   0.5346787
6      wt numeric 32       0            0       29   3.217250   0.9784574
7    qsec numeric 32       0            0       30  17.848750   1.7869432
8      vs numeric 32       0            0        2   0.437500   0.5040161
9      am numeric 32       0            0        2   0.406250   0.4989909
10   gear numeric 32       0            0        3   3.687500   0.7378041
      min       q25  median    q75     max top
1  10.400  15.42500  19.200  22.80  33.900    
2   4.000   4.00000   6.000   8.00   8.000    
3  71.100 120.82500 196.300 326.00 472.000    
4  52.000  96.50000 123.000 180.00 335.000    
5   2.760   3.08000   3.695   3.92   4.930    
6   1.513   2.58125   3.325   3.61   5.424    
7  14.500  16.89250  17.710  18.90  22.900    
8   0.000   0.00000   0.000   1.00   1.000    
9   0.000   0.00000   0.000   1.00   1.000    
10  3.000   3.00000   4.000   4.00   5.000    
# 1 more rows</code></pre>
</div>
</div>
</section></section><section id="performance" class="level2"><h2 class="anchored" data-anchor-id="performance">Performance</h2>
<p>Timing and memory below come from the <a href="https://bench.r-lib.org"><code>bench</code></a> package at 1,000,000 rows on one Linux machine. The script that produced both figures and both tables is <a href="https://github.com/ielbadisy/basetable/blob/main/inst/benchmarks/make-readme-figures.R"><code>inst/benchmarks/make-readme-figures.R</code></a>; the <a href="https://github.com/ielbadisy/basetable/blob/main/vignettes/benchmarking.Rmd"><code>Benchmarks</code> vignette</a> has the full reproducible report. <code>basetable</code> is compared with <code>data.table</code> and <code>dplyr</code>.</p>
<section id="speed" class="level3"><h3 class="anchored" data-anchor-id="speed">Speed</h3>
<div class="quarto-figure quarto-figure-center">
<figure class="figure"><p><a href="benchmark-time.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1" title="Median runtime by engine at 1e6 rows"><img src="https://elbadisyimad.com/blog/2026-09-05-basetable-tutorial/benchmark-time.png" class="img-fluid figure-img" alt="Median runtime by engine at 1e6 rows"></a></p>
<figcaption>Median runtime by engine at 1e6 rows</figcaption></figure>
</div>
</section><section id="memory" class="level3"><h3 class="anchored" data-anchor-id="memory">Memory</h3>
<div class="quarto-figure quarto-figure-center">
<figure class="figure"><p><a href="benchmark-memory.png" class="lightbox" data-gallery="quarto-lightbox-gallery-2" title="Memory allocated by engine at 1e6 rows"><img src="https://elbadisyimad.com/blog/2026-09-05-basetable-tutorial/benchmark-memory.png" class="img-fluid figure-img" alt="Memory allocated by engine at 1e6 rows"></a></p>
<figcaption>Memory allocated by engine at 1e6 rows</figcaption></figure>
</div>
<table class="caption-top table">
<colgroup>
<col style="width: 11%">
<col style="width: 14%">
<col style="width: 14%">
<col style="width: 14%">
<col style="width: 14%">
<col style="width: 14%">
<col style="width: 14%">
</colgroup>
<thead><tr class="header">
<th>Operation</th>
<th style="text-align: right;">basetable</th>
<th style="text-align: right;">data.table</th>
<th style="text-align: right;">dplyr</th>
<th style="text-align: right;">basetable mem</th>
<th style="text-align: right;">data.table mem</th>
<th style="text-align: right;">dplyr mem</th>
</tr></thead>
<tbody>
<tr class="odd">
<td>filter</td>
<td style="text-align: right;">7 ms</td>
<td style="text-align: right;">10 ms</td>
<td style="text-align: right;">10 ms</td>
<td style="text-align: right;">15 MB</td>
<td style="text-align: right;">21 MB</td>
<td style="text-align: right;">28 MB</td>
</tr>
<tr class="even">
<td>sort (string key)</td>
<td style="text-align: right;">58 ms</td>
<td style="text-align: right;">44 ms</td>
<td style="text-align: right;">102 ms</td>
<td style="text-align: right;">34 MB</td>
<td style="text-align: right;">47 MB</td>
<td style="text-align: right;">69 MB</td>
</tr>
<tr class="odd">
<td>distinct</td>
<td style="text-align: right;">5 ms</td>
<td style="text-align: right;">8 ms</td>
<td style="text-align: right;">13 ms</td>
<td style="text-align: right;">0.03 MB</td>
<td style="text-align: right;">20 MB</td>
<td style="text-align: right;">12 MB</td>
</tr>
<tr class="even">
<td>count by group</td>
<td style="text-align: right;">23 ms</td>
<td style="text-align: right;">40 ms</td>
<td style="text-align: right;">738 ms</td>
<td style="text-align: right;">1 MB</td>
<td style="text-align: right;">30 MB</td>
<td style="text-align: right;">30 MB</td>
</tr>
<tr class="odd">
<td>sd by group</td>
<td style="text-align: right;">10 ms</td>
<td style="text-align: right;">16 ms</td>
<td style="text-align: right;">42 ms</td>
<td style="text-align: right;">0.05 MB</td>
<td style="text-align: right;">27 MB</td>
<td style="text-align: right;">36 MB</td>
</tr>
<tr class="even">
<td>equi join</td>
<td style="text-align: right;">16 ms</td>
<td style="text-align: right;">15 ms</td>
<td style="text-align: right;">66 ms</td>
<td style="text-align: right;">8 MB</td>
<td style="text-align: right;">8 MB</td>
<td style="text-align: right;">101 MB</td>
</tr>
<tr class="odd">
<td>semi join</td>
<td style="text-align: right;">13 ms</td>
<td style="text-align: right;">67 ms</td>
<td style="text-align: right;">52 ms</td>
<td style="text-align: right;">4 MB</td>
<td style="text-align: right;">58 MB</td>
<td style="text-align: right;">82 MB</td>
</tr>
</tbody>
</table>
<p>(<code>equi join</code> pins <code>data.table</code> to <code>sort = FALSE</code>, matching <code><a href="https://rdrr.io/pkg/basetable/man/merge.html">basetable::merge()</a></code>, which returns rows in input order.)</p>
<p><code>basetable</code> is faster than <code>data.table</code> on <code>filter</code>, <code>distinct</code>, grouped <code>count</code>, <code>sd</code> by group and <code>semi join</code>, and is level with it on <code>equi join</code>. Against <code>dplyr</code> it is faster on every operation here, by more than 30x on high-cardinality <code>count</code>. The one operation it loses is string <code>sort</code>.</p>
</section><section id="memory-ranked-by-advantage" class="level3"><h3 class="anchored" data-anchor-id="memory-ranked-by-advantage">Memory, ranked by advantage</h3>
<p><code>basetable</code> allocates the least (or tied least) on every operation measured. The size of the edge splits in two: overwhelming on grouped reductions, where the result is tiny and nothing intermediate is materialised in R; modest on operations that return a full table, where the output frame itself sets a floor.</p>
<table class="caption-top table">
<thead><tr class="header">
<th>Operation</th>
<th style="text-align: right;">basetable</th>
<th style="text-align: right;">data.table</th>
<th style="text-align: right;">dplyr</th>
<th style="text-align: right;">basetable vs data.table</th>
</tr></thead>
<tbody>
<tr class="odd">
<td>distinct</td>
<td style="text-align: right;">0.03 MB</td>
<td style="text-align: right;">20 MB</td>
<td style="text-align: right;">12 MB</td>
<td style="text-align: right;">~700x less</td>
</tr>
<tr class="even">
<td>sd by group</td>
<td style="text-align: right;">0.05 MB</td>
<td style="text-align: right;">27 MB</td>
<td style="text-align: right;">36 MB</td>
<td style="text-align: right;">~500x less</td>
</tr>
<tr class="odd">
<td>count by group</td>
<td style="text-align: right;">1 MB</td>
<td style="text-align: right;">30 MB</td>
<td style="text-align: right;">30 MB</td>
<td style="text-align: right;">~30x less</td>
</tr>
<tr class="even">
<td>semi join</td>
<td style="text-align: right;">4 MB</td>
<td style="text-align: right;">58 MB</td>
<td style="text-align: right;">82 MB</td>
<td style="text-align: right;">~15x less</td>
</tr>
<tr class="odd">
<td>filter</td>
<td style="text-align: right;">15 MB</td>
<td style="text-align: right;">21 MB</td>
<td style="text-align: right;">28 MB</td>
<td style="text-align: right;">~1.4x less</td>
</tr>
<tr class="even">
<td>sort (string key)</td>
<td style="text-align: right;">34 MB</td>
<td style="text-align: right;">47 MB</td>
<td style="text-align: right;">69 MB</td>
<td style="text-align: right;">~1.4x less</td>
</tr>
<tr class="odd">
<td>equi join</td>
<td style="text-align: right;">8 MB</td>
<td style="text-align: right;">8 MB</td>
<td style="text-align: right;">101 MB</td>
<td style="text-align: right;">~parity</td>
</tr>
</tbody>
</table>
<p>These are R-level allocations as reported by <code>bench</code>. The C++ engine also uses <code>malloc</code>’d scratch buffers (radix keys, per-thread row-position vectors) that <code>bench</code> does not count, so peak process memory during a sort or filter is higher than the figure above; <code>data.table</code> does the same.</p>
<p>The one gap is <strong>sorting</strong>: <code>orderrows()</code> is a stable parallel radix, ~20x faster than base <code><a href="https://rdrr.io/r/base/order.html">order()</a></code>, but still ~1.3x of <code>data.table</code>, whose hand-tuned parallel radix is the one operation <code>basetable</code> does not match.</p>
</section></section><section id="positioning" class="level2"><h2 class="anchored" data-anchor-id="positioning">Positioning</h2>
<p><code>data.table</code> is faster on some workloads (notably sorting) and has a far larger ecosystem; <code>dplyr</code> is the tidyverse standard. <code>basetable</code> is a good fit when you want:</p>
<ul>
<li>
<strong>base-R syntax</strong> and semantics, not <code>[i, j, by]</code>, tidy evaluation, or a method-chained frame object;</li>
<li>
<strong>no dependencies</strong> to install, pin, or reason about;</li>
<li>a package small enough to <strong>read end to end</strong>, teach from, and hand to a language model as a stable target;</li>
<li>competitive speed and best-in-class memory on the everyday operations (filter, group, join, distinct) without changing how you write code.</li>
</ul>
<p>Grouping is a <code>by</code> argument on the verb that needs it (<code><a href="https://rdrr.io/r/stats/aggregate.html">aggregate()</a></code>, <code>count()</code>, <code>summaries()</code>, <code><a href="https://rdrr.io/r/base/transform.html">transform()</a></code>, <code><a href="https://rdrr.io/r/base/subset.html">subset()</a></code>, <code>samplerows()</code>, <code>firstby()</code>, …), not a stateful <code>group_by()</code>. The group is named at the call and never persists, so there is no <code>ungroup()</code> to forget.</p>
</section><section id="using-basetable-alongside-dplyr-and-data.table" class="level2"><h2 class="anchored" data-anchor-id="using-basetable-alongside-dplyr-and-data.table">Using basetable alongside dplyr and data.table</h2>
<p><code>basetable</code> reuses base-R verb names (<code><a href="https://rdrr.io/r/base/subset.html">subset()</a></code>, <code><a href="https://rdrr.io/r/base/merge.html">merge()</a></code>, <code><a href="https://rdrr.io/r/base/transform.html">transform()</a></code>, <code><a href="https://rdrr.io/r/base/split.html">split()</a></code>, <code><a href="https://rdrr.io/r/stats/aggregate.html">aggregate()</a></code>) on purpose. It does <strong>not</strong> ship the dplyr-coined verbs (<code><a href="https://rdrr.io/r/stats/filter.html">filter()</a></code>, <code>select()</code>, <code>mutate()</code>, <code>arrange()</code>, <code>summarise()</code>, <code>distinct()</code>, <code>glimpse()</code>, …), so it can be attached next to <code>dplyr</code> without shadowing its grammar. The two names it shares with <code>dplyr</code> are <code>count()</code> and <code>pick()</code>, kept because they read as base-style verbs; with both packages attached, whichever was attached <strong>last</strong> wins for those (and for the base-R names <code>data.table</code> also defines). Two fixes:</p>
<ul>
<li>call it explicitly: <code>basetable::transform(...)</code>;</li>
<li>or <code>conflicted::conflict_prefer("transform", "basetable")</code> once per session.</li>
</ul></section><section id="operation-dictionary" class="level2"><h2 class="anchored" data-anchor-id="operation-dictionary">Operation dictionary</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead><tr class="header">
<th>Family</th>
<th>Exported functions</th>
<th>Base reference</th>
</tr></thead>
<tbody>
<tr class="odd">
<td>Row subsetting</td>
<td><code><a href="https://rdrr.io/r/base/subset.html">subset()</a></code></td>
<td><code><a href="https://rdrr.io/r/base/subset.html">base::subset()</a></code></td>
</tr>
<tr class="even">
<td>Column keep / drop / rename</td>
<td>
<code>pick()</code>, <code><a href="https://rdrr.io/r/base/drop.html">drop()</a></code>, <code>renamecols()</code>
</td>
<td>
<code>[</code>, <code>names&lt;-()</code>
</td>
</tr>
<tr class="odd">
<td>Transformation</td>
<td>
<code><a href="https://rdrr.io/r/base/transform.html">transform()</a></code>, <code><a href="https://rdrr.io/r/base/with.html">within()</a></code>
</td>
<td>base equivalents</td>
</tr>
<tr class="even">
<td>Ordering</td>
<td><code>orderrows()</code></td>
<td><code><a href="https://rdrr.io/r/base/order.html">order()</a></code></td>
</tr>
<tr class="odd">
<td>Distinct / duplicates</td>
<td>
<code>uniquerows()</code>, <code>duplicaterows()</code>, <code>removeduplicates()</code>
</td>
<td>
<code><a href="https://rdrr.io/r/base/unique.html">unique()</a></code>, <code><a href="https://rdrr.io/r/base/duplicated.html">duplicated()</a></code>
</td>
</tr>
<tr class="even">
<td>Aggregation</td>
<td>
<code><a href="https://rdrr.io/r/stats/aggregate.html">aggregate()</a></code>, <code>count()</code>, <code>summaries()</code>
</td>
<td>
<code><a href="https://rdrr.io/r/stats/aggregate.html">aggregate()</a></code>, <code><a href="https://rdrr.io/r/base/table.html">table()</a></code>
</td>
</tr>
<tr class="odd">
<td>Recoding</td>
<td>
<code>recode()</code>, <code>collapsevalues()</code>, <code>casewhen()</code>, <code>replacewhere()</code>
</td>
<td>
<code><a href="https://rdrr.io/r/base/ifelse.html">ifelse()</a></code>, <code><a href="https://rdrr.io/r/base/switch.html">switch()</a></code>
</td>
</tr>
<tr class="even">
<td>Joins</td>
<td>
<code><a href="https://rdrr.io/r/base/merge.html">merge()</a></code>, <code>semimerge()</code>, <code>antimerge()</code>, <code>updatemerge()</code>, <code>crossmerge()</code>, <code>nonequimerge()</code>, <code>overlapmerge()</code>, <code>rangemerge()</code>, <code>rollingmerge()</code>
</td>
<td><code><a href="https://rdrr.io/r/base/merge.html">merge()</a></code></td>
</tr>
<tr class="odd">
<td>Row / column bind</td>
<td><code>rbindfill()</code></td>
<td><code><a href="https://rdrr.io/r/base/cbind.html">rbind()</a></code></td>
</tr>
<tr class="even">
<td>Split / apply</td>
<td>
<code><a href="https://rdrr.io/r/base/split.html">split()</a></code>, <code>applyby()</code>
</td>
<td><code><a href="https://rdrr.io/r/base/split.html">split()</a></code></td>
</tr>
<tr class="odd">
<td>Reshaping</td>
<td>
<code>tolong()</code>, <code>towide()</code>, <code><a href="https://rdrr.io/r/stats/reshape.html">reshape()</a></code>, <code><a href="https://rdrr.io/r/utils/stack.html">stack()</a></code>, <code><a href="https://rdrr.io/r/utils/stack.html">unstack()</a></code>
</td>
<td>base equivalents</td>
</tr>
<tr class="even">
<td>Completion</td>
<td><code>completegrid()</code></td>
<td>
<code><a href="https://rdrr.io/r/base/expand.grid.html">expand.grid()</a></code> + join</td>
</tr>
<tr class="odd">
<td>File I/O</td>
<td>
<code>btread()</code>, <code>btwrite()</code>; <code><a href="https://rdrr.io/r/stats/aggregate.html">aggregate()</a></code> / <code>count()</code> / <code>uniquerows()</code> / <code>freq()</code> also take a file path</td>
<td>
<code><a href="https://rdrr.io/r/utils/read.table.html">read.delim()</a></code>, fused file to result</td>
</tr>
<tr class="even">
<td>Inspection</td>
<td>
<code>preview()</code>, <code>dims()</code>, <code>types()</code>, <code>headtail()</code>
</td>
<td>
<code><a href="https://rdrr.io/r/utils/str.html">str()</a></code>, <code><a href="https://rdrr.io/r/base/dim.html">dim()</a></code>, <code><a href="https://rdrr.io/r/utils/head.html">head()</a></code>
</td>
</tr>
<tr class="odd">
<td>EDA</td>
<td>
<code>describe()</code>, <code>missingness()</code>, <code><a href="https://rdrr.io/r/stats/profile.html">profile()</a></code>, <code>freq()</code>, <code>summarytab()</code>, <code>compare()</code>
</td>
<td>base summaries</td>
</tr>
</tbody>
</table>
<p><code>btread()</code> memory-maps the file and, with <code>lazy = TRUE</code>, returns columns as ALTREP vectors parsed on first access. <code><a href="https://rdrr.io/r/stats/aggregate.html">aggregate()</a></code>, <code>count()</code>, <code>uniquerows()</code> and <code>freq()</code> accept a single file path as their first argument and fuse the parse with the grouping, so unused columns are never materialised.</p>
</section><section id="status" class="level2"><h2 class="anchored" data-anchor-id="status">Status</h2>
<p>Every exported function has direct test coverage. Vignettes cover getting started, data manipulation, exploration, a complete function reference, and benchmarks. CI checks release R on Linux, macOS and Windows plus oldrel and devel.</p>
<hr>
<footer><a href="../../index.html#blog">Back to blog</a>
</footer>

</section></section><a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>R</category>
  <category>packages</category>
  <category>tutorial</category>
  <guid>https://elbadisyimad.com/blog/2026-09-05-basetable-tutorial/</guid>
  <pubDate>Fri, 04 Sep 2026 23:00:00 GMT</pubDate>
</item>
<item>
  <title>API Design in the Era of LLMs</title>
  <dc:creator>Imad El Badisy</dc:creator>
  <link>https://elbadisyimad.com/blog/2026-08-27-api-design-in-the-era-of-llms/</link>
  <description><![CDATA[ 





<p>This is an opinion piece, and it’s one I’ve held for a while, building <code>funcml</code>, but the last couple of years of coding assistants have sharpened it into something more specific: keeping a public interface stable isn’t just being polite to your users anymore. It’s starting to be part of whether your software is correct.</p>
<section id="the-claim" class="level2">
<h2 class="anchored" data-anchor-id="the-claim">The claim</h2>
<p>A library has two audiences now. There’s the person who reads today’s documentation and writes code against the current version - that’s the old audience, still there. And then there’s every language model trained on the public record of how your library has been used across all its past versions, which is new and honestly enormous. That second audience doesn’t read your changelog. It has no way to tell a current idiom from one you retired four years ago. It just reproduces whatever pattern showed up most in its training data, and it does that with total confidence, no version awareness at all.</p>
<p>If your API hasn’t changed much, both audiences land on the same answer. If it has churned, the model turns into something that hands out code that no longer runs - or, worse, code that runs but doesn’t mean what it used to.</p>
<p>Interface stability used to be about usability. Now it’s closer to a correctness guarantee, because a lot of the code written against your library is going to be generated by something whose knowledge is an average over your whole history, not a snapshot of where you are today.</p>
</section>
<section id="what-actually-changed" class="level2">
<h2 class="anchored" data-anchor-id="what-actually-changed">What actually changed</h2>
<p>A few things happened around the same time.</p>
<p>People stopped searching and started generating. A few years ago, if you got stuck on an API you searched, skimmed a few results, checked the dates, and adjusted. That reconciliation happened in your head. Now people ask a model and paste what it gives them, and the model isn’t doing that reconciliation for you.</p>
<p>The training data skews old. The public writing about any library that’s been around a while is weighted toward its early, most-discussed years - every retired function, every old argument, every outdated convention, still indexed, still upvoted, still sitting in a tutorial nobody updated. More documentation doesn’t fix an unstable API. It just preserves every past state of it as competing advice with no dates attached.</p>
<p>And confidence doesn’t track how current something is. A stale forum post at least has a timestamp. A model’s answer doesn’t. It’ll hand you a deprecated idiom as fluently as a current one, and you won’t know anything’s wrong until it breaks - or, if the behavior just quietly changed instead of breaking outright, maybe you never find out at all.</p>
<p>Put together: the older and more heavily documented a moving API is, the more likely a model is to hand a newcomer something subtly wrong. Which runs against the usual instinct that more documentation is always better.</p>
</section>
<section id="a-few-rules-i-try-to-follow" class="level2">
<h2 class="anchored" data-anchor-id="a-few-rules-i-try-to-follow">A few rules I try to follow</h2>
<p>None of this is new advice. What’s changed is the cost of ignoring it.</p>
<p>Keep the surface small and orthogonal - a handful of verbs that compose (<code>fit</code>, <code>evaluate</code>, <code>tune</code>, <code>cv</code>, <code>compare</code>, <code>interpret</code>, <code>estimate</code>) beats fifty specialized functions. Fewer entry points means fewer things to explain, fewer ways to get it wrong, and less that can drift out from under you. It also means one person can actually hold the whole thing in their head, which is the only way it stays coherent for years.</p>
<p>Own your contracts. Decide for yourself what a fitted object contains, what <code>predict</code> returns, how a factor outcome gets handled, what a probability column looks like. Hand those decisions off to a stack of upstream packages and every design change they make becomes a change in your behavior that you didn’t choose and can’t veto.</p>
<p>Prefer shallow dependencies on stable parts. Calling <code>ranger</code>, <code>glmnet</code>, <code>xgboost</code>, and base <code>stats</code> directly means each dependency is small, single-purpose, and hasn’t moved much in a decade. Building on a large coordinated ecosystem instead means you’ve signed up to track that ecosystem’s lifecycle forever. Both are dependencies - only one of them is an ongoing maintenance bill.</p>
<p>Treat deprecation as a failure, not a feature. A formal deprecation process is honest and a long warning window is considerate, but a deprecation is still an admission that the interface was wrong and that everyone downstream now has work to do. For infrastructure code, the target rate of breaking changes should be close to zero. Depend on something that deprecates on a regular cadence and you’ve inherited that cadence.</p>
<p>Write documentation that ages well - examples that exercise the stable core rather than showing off a new argument, dates on your posts, and if you have to show an old way next to a new way, label them so there’s no ambiguity. Assume a model is going to ingest the page with zero context and reproduce whatever’s on it.</p>
<p>And where you can, make formulas and plain data frames the interface. They’re about the most stable contract R has, and an API built on them inherits that permanence instead of the churn of a bespoke specification object.</p>
</section>
<section id="a-pattern-i-distrust" class="level2">
<h2 class="anchored" data-anchor-id="a-pattern-i-distrust">A pattern I distrust</h2>
<p>The thing I’m most wary of is the wrapper built on a wrapper - a convenience package whose whole pitch is a simple front door, sitting on top of a deep, still-evolving stack of other packages.</p>
<p>I get the appeal. You get breadth fast, you inherit a big community’s testing, and the individual pieces are often genuinely good. But the reliability of the result isn’t something the author of the top layer actually controls - it’s the union of every layer’s failure modes underneath it. A change in low-level evaluation semantics, a reordering of columns somewhere in preprocessing, a shifted default three packages down, and any of it can surface as a wrong answer at the top, with the top-level author only able to wait it out or work around it.</p>
<p>You can see this in the release history of packages like this: lots of releases in a short window, most of them not adding anything new but fixing core behavior that turned out to be wrong, or patching around something upstream that broke. That’s not a package hardening on solid ground. That’s a package discovering its ground keeps moving - which is the opposite of what a long release history is usually taken to mean.</p>
<p>Automated ML wrappers get hit hardest here, since their entire job is to hide the stack. When the hidden stack shifts, users have no way to even notice, and the model they ask for help has been trained on years of the stack’s older shapes. The abstraction meant to protect the newcomer ends up being exactly what stops them from seeing what went wrong.</p>
<p>None of this is against large ecosystems in general - they’re fine for prototyping, fine for learning. It’s against building one underneath a package that’s marketed on durability and then acting surprised when the durability doesn’t show up.</p>
</section>
<section id="why-i-actually-care-about-this" class="level2">
<h2 class="anchored" data-anchor-id="why-i-actually-care-about-this">Why I actually care about this</h2>
<p>There’s a question underneath all of this about what we think a library even is.</p>
<p>One way to see it: a library is alive. It grows, sheds old parts, follows whatever the current best thinking is, and users are expected to move along with it. Deprecation is just healthy metabolism, and the old code sitting out there in the world is dead weight - not really the project’s problem if a model keeps resurrecting it.</p>
<p>The other way: a published interface is closer to a promise. Once people build on it, its shape stops being entirely yours to change. Base R takes this line - <code>lm</code>, <code>predict</code>, <code>model.matrix</code> have meant the same thing for decades, and that’s exactly what let a whole scientific literature of reproducible code pile up on top of them. The value isn’t in any one function being elegant. It’s that code written against them in 2005 still runs and still means the same thing today.</p>
<p>I hold the second view, and honestly the arrival of models that write code for people has only made me more sure of it. We’re now writing interfaces that will be consumed at scale by something with no sense of time, and everything we ship becomes training data eventually. A stable, modest, self-owned API is a small courtesy to a future where most of the code calling your library was written by something that learned it from your past, not your present.</p>
<p>Wanting to build something that lasts, with few parts and visible joints, has always been partly an aesthetic preference. Now it also happens to be the practical one. If the main reader of your code is going to be a model averaging over your history, the best thing you can do is not give it much history to average over.</p>
<hr>
<footer>
<a href="../../index.html#blog">Back to blog</a>
</footer>


</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>R</category>
  <category>machine-learning</category>
  <category>essay</category>
  <guid>https://elbadisyimad.com/blog/2026-08-27-api-design-in-the-era-of-llms/</guid>
  <pubDate>Wed, 26 Aug 2026 23:00:00 GMT</pubDate>
</item>
<item>
  <title>Abstraction versus Reality</title>
  <dc:creator>Imad El Badisy</dc:creator>
  <link>https://elbadisyimad.com/blog/2026-08-24-causality-and-abstraction/</link>
  <description><![CDATA[ 





<p>I think about the farm fantasy sometimes, the one where you quit and go grow vegetables. It’s not really about rejecting technology. It’s about wanting your effort to leave a trace again. Half of what I do in a day disappears into abstractions - a bug fixed, a metric moved, a notification cleared - and none of it is visible the next morning unless I go looking for it. Plant something and water it, and by the weekend you can see the difference.</p>
<p>So maybe it’s not technology versus nature. It’s abstraction versus something you can put your hands on. I can live through a screen fine. I just don’t fully believe I’ve done anything until I can touch it.</p>
<hr>
<footer>
<a href="../../index.html#blog">Back to blog</a>
</footer>



<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>essay</category>
  <guid>https://elbadisyimad.com/blog/2026-08-24-causality-and-abstraction/</guid>
  <pubDate>Sun, 23 Aug 2026 23:00:00 GMT</pubDate>
</item>
<item>
  <title>What I Learned from the GMDS Biostatistics Competition 2026</title>
  <dc:creator>Imad El Badisy</dc:creator>
  <link>https://elbadisyimad.com/blog/2026-08-20-gmds-biostatistics-competition-2026/</link>
  <description><![CDATA[ 





<p>I signed up for the GMDS Biostatistics Competition 2026 mostly to test something I’d been curious about for a while: whether heterogeneous treatment effect estimation gets more robust if you combine several learners instead of picking one and trusting it.</p>
<p>My submission ran a single R pipeline across the five competition tasks. I estimated individual treatment effects with a handful of approaches - random forests, elastic-net models, gradient boosting, and causal forests<sup>1</sup> - and then combined their subgroup assignments through a co-association consensus step inspired by Evidence Accumulation Clustering.</p>
<p>What made the competition useful wasn’t just finding out whether the overall approach worked. It was seeing exactly which parts of the pipeline held up and which ones didn’t.</p>
<section id="what-worked" class="level2">
<h2 class="anchored" data-anchor-id="what-worked">What worked</h2>
<p>Combining complementary evidence turned out to help with detecting treatment effect heterogeneity in the first place. I used three signals here - the GRF calibration test, an interaction test between treatment and the estimated subgroup, and a comparison of treatment effects between the subgroup and its complement - and decided by majority vote. That left me more convinced that HTE detection shouldn’t lean on a single diagnostic.</p>
<p>The consensus framework also did a reasonable job estimating how large the treatment-responsive subgroup was overall, even in cases where individual patient assignments were shaky. Ensemble methods seem to recover the population-level structure before they recover the individual-level labels.</p>
</section>
<section id="what-i-would-change" class="level2">
<h2 class="anchored" data-anchor-id="what-i-would-change">What I would change</h2>
<p>A few things didn’t hold up as well, and I’d do them differently next time.</p>
<section id="variable-selection-needs-its-own-ensemble-strategy" class="level3">
<h3 class="anchored" data-anchor-id="variable-selection-needs-its-own-ensemble-strategy">1. Variable selection needs its own ensemble strategy</h3>
<p>I used elastic-net regression with treatment-covariate interactions to separate predictive variables from prognostic ones - non-zero interaction coefficients as predictive, non-zero main effects as prognostic. In hindsight this leaned on a single model too heavily, and <code>lambda.min</code> is tuned for predictive performance, not for recovering the true sparse structure. Things I’d try instead: stability selection, stronger penalization like <code>lambda.1se</code>, hierarchical interaction selection, importance measures from causal forests, and consensus variable selection across several HTE learners. Basically the same ensemble idea I used for treatment effects, applied one step earlier to variable discovery.</p>
</section>
<section id="dont-binarize-cate-estimates-too-early" class="level3">
<h3 class="anchored" data-anchor-id="dont-binarize-cate-estimates-too-early">2. Don’t binarize CATE estimates too early</h3>
<p>For subgroup assignment, each learner’s CATE estimate got collapsed into a binary benefiter / non-benefiter call based on whether it was above or below zero, and those binary calls fed the co-association matrix. Simple, robust, and it throws away a lot of information: a predicted effect of <code>0.001</code> gets the same label as <code>1.5</code>, while two estimates that are both close to zero but on opposite sides of it get treated as completely different.</p>
<p>Next time I’d keep the continuous CATE predictions around longer and build the consensus straight from standardized treatment-effect estimates - cluster patients on the matrix</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cleft%5B%0A%5Chat%7B%5Ctau%7D_%7BRF%7D,%5C;%0A%5Chat%7B%5Ctau%7D_%7Bglmnet%7D,%5C;%0A%5Chat%7B%5Ctau%7D_%7BXGB%7D,%5C;%0A%5Chat%7B%5Ctau%7D_%7BGRF%7D%0A%5Cright%5D.%0A"></p>
<p>This would allow both the direction and magnitude of predicted treatment benefit to contribute to the consensus.</p>
</section>
<section id="subgroup-discovery-and-treatment-effect-estimation-must-be-separated" class="level3">
<h3 class="anchored" data-anchor-id="subgroup-discovery-and-treatment-effect-estimation-must-be-separated">3. Subgroup discovery and treatment-effect estimation must be separated</h3>
<p>This is probably the most important lesson.</p>
<p>After identifying the subgroup, I estimated treatment effects within it and its complement using AIPW via <code>grf::average_treatment_effect()</code>. The problem is that the same dataset fed both steps: patients get selected partly because they look like they have a large treatment effect, and then the treatment effect gets estimated in that same selected group. AIPW is a good estimator, but it doesn’t fix bias that comes from data-adaptive subgroup selection on its own.</p>
<p>What I’d do instead is cross-fit the whole thing: build the CATE model and subgroup rule on a training fold,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7Btraining%20data%7D%20%5Crightarrow%20%5Ctext%7BCATE%20model%7D%20%5Crightarrow%20%5Ctext%7Bsubgroup%20rule%7D%0A"></p>
<p>then apply that rule to a held-out fold and estimate the effect only there,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7Bout-of-fold%20patients%7D%20%5Crightarrow%20%5Ctext%7Bsubgroup%20assignment%7D%20%5Crightarrow%20%5Ctext%7Btreatment-effect%20estimation%7D.%0A"></p>
<p>Repeating that across folds should stabilize both the subgroup membership and the effect estimates.</p>
</section>
</section>
<section id="the-broader-lesson" class="level2">
<h2 class="anchored" data-anchor-id="the-broader-lesson">The broader lesson</h2>
<p>The thing I keep coming back to is that good subgroup discovery doesn’t automatically give you good treatment-effect estimation. “Heterogeneous treatment effect analysis” is really several different problems stacked on top of each other:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7BDetect%20HTE%7D%20%5Cneq%20%5Ctext%7BIdentify%20modifiers%7D%20%5Cneq%20%5Ctext%7BAssign%20patients%7D%20%5Cneq%20%5Ctext%7BEstimate%20subgroup%20prevalence%7D%20%5Cneq%20%5Ctext%7BEstimate%20subgroup%20treatment%20effects%7D.%0A"></p>
<p>A method can be good at one of these and bad at another, and it’s easy to miss that if you only evaluate the pipeline end to end. Next time I’d rather design around these pieces separately - ensemble CATE estimation, consensus variable selection, continuous consensus subgrouping, cross-fitting, and independent effect estimation - and then wire them together, instead of treating the pipeline as one black box.</p>
<p>That’s probably the real value of entering a competition like this: not the ranking, but finding out exactly where a pipeline that looked fine end-to-end breaks once you check each piece on its own. I’ll be carrying these lessons into the next version.</p>
<hr>
<footer>
<a href="../../index.html#blog">Back to blog</a>
</footer>


</section>


<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a><div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>The pipeline was built in R using <a href="https://grf-labs.github.io/grf/">grf</a> for causal forests, the GRF calibration test, and AIPW average treatment effect estimation; <a href="https://glmnet.stanford.edu/">glmnet</a> for elastic-net variable selection; and <a href="https://xgboost.readthedocs.io/">xgboost</a> for gradient-boosted CATE estimation. The co-association consensus step was inspired by Evidence Accumulation Clustering (Fred &amp; Jain, 2005, <em>IEEE TPAMI</em>).↩︎</p></li>
</ol>
</section></div> ]]></description>
  <category>R</category>
  <category>causal-inference</category>
  <category>biostatistics</category>
  <category>machine-learning</category>
  <guid>https://elbadisyimad.com/blog/2026-08-20-gmds-biostatistics-competition-2026/</guid>
  <pubDate>Wed, 19 Aug 2026 23:00:00 GMT</pubDate>
</item>
<item>
  <title>survalis is now on CRAN</title>
  <dc:creator>Imad El Badisy</dc:creator>
  <link>https://elbadisyimad.com/blog/2026-08-18-survalis-cran-release/</link>
  <description><![CDATA[ <p><code>survalis</code> is now on CRAN: <a href="https://CRAN.R-project.org/package=survalis">CRAN.R-project.org/package=survalis</a>. It provides one consistent interface, <code>fit_*()</code> / <code>predict_*()</code> pairs returning a standardized <code>mlsurv_model</code> and a survival-probability matrix, across 19 survival learners (semiparametric, parametric, tree-based, ensemble, boosting, kernel, and deep-learning), plus benchmarking, evaluation, calibration, and model-agnostic interpretation on top.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/utils/install.packages.html">install.packages</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"survalis"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<p>This post walks through what changed between the first CRAN submission candidate (0.7.0) and the current release (0.9.0): the new implementations, and the corrections made along the way.</p>
<section id="one-entry-point-for-benchmarking-benchmark" class="level2"><h2 class="anchored" data-anchor-id="one-entry-point-for-benchmarking-benchmark">One entry point for benchmarking: <code>benchmark()</code>
</h2>
<p>Comparing learners used to mean choosing between <code><a href="https://rdrr.io/pkg/survalis/man/benchmark_default_survlearners.html">benchmark_default_survlearners()</a></code> (plain k-fold CV) and <code><a href="https://rdrr.io/pkg/survalis/man/benchmark_tuned_survlearners.html">benchmark_tuned_survlearners()</a></code> (nested CV with per-learner hyperparameter tuning). <code><a href="https://rdrr.io/pkg/survalis/man/benchmark.html">benchmark()</a></code> now dispatches to either from a single <code>tune</code> argument:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;"><a href="https://rdrr.io/r/base/library.html">library</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;"><a href="https://CRAN.R-project.org/package=survalis">survalis</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;"><a href="https://rdrr.io/r/base/library.html">library</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;"><a href="https://github.com/therneau/survival">survival</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">res</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survalis/man/benchmark.html">benchmark</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span></span>
<span>  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survival/man/Surv.html">Surv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">time</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">status</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">age</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">karno</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">celltype</span>,</span>
<span>  data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">veteran</span>,</span>
<span>  learners <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"coxph"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rsf"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>,</span>
<span>  times <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span>,</span>
<span>  metrics <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cindex"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ibs"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>,</span>
<span>  tune <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>,</span>
<span>  folds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,</span>
<span>  seed <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">res</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>         splits    id fold metric value learner
1  list(trt.... Fold1    1 cindex 0.739   coxph
2  list(trt.... Fold1    1    ibs 0.173   coxph
3  list(trt.... Fold2    2 cindex 0.697   coxph
4  list(trt.... Fold2    2    ibs 0.156   coxph
5  list(trt.... Fold3    3 cindex 0.703   coxph
6  list(trt.... Fold3    3    ibs 0.166   coxph
7  list(trt.... Fold4    4 cindex 0.717   coxph
8  list(trt.... Fold4    4    ibs 0.168   coxph
9  list(trt.... Fold5    5 cindex 0.754   coxph
10 list(trt.... Fold5    5    ibs 0.152   coxph
11 list(trt.... Fold1    1 cindex 0.636     rsf
12 list(trt.... Fold1    1    ibs 0.171     rsf
13 list(trt.... Fold2    2 cindex 0.697     rsf
14 list(trt.... Fold2    2    ibs 0.172     rsf
15 list(trt.... Fold3    3 cindex 0.720     rsf
16 list(trt.... Fold3    3    ibs 0.158     rsf
17 list(trt.... Fold4    4 cindex 0.677     rsf
18 list(trt.... Fold4    4    ibs 0.188     rsf
19 list(trt.... Fold5    5 cindex 0.722     rsf
20 list(trt.... Fold5    5    ibs 0.151     rsf</code></pre>
</div>
</div>
<p><code>tune = TRUE</code> runs the same call as nested CV, dispatching to <code><a href="https://rdrr.io/pkg/survalis/man/benchmark_tuned_survlearners.html">benchmark_tuned_survlearners()</a></code> with <code>outer_folds</code>/<code>inner_folds</code> instead. <code><a href="https://rdrr.io/pkg/survalis/man/benchmark_default_survlearners.html">benchmark_default_survlearners()</a></code> and <code><a href="https://rdrr.io/pkg/survalis/man/benchmark_tuned_survlearners.html">benchmark_tuned_survlearners()</a></code> both remain available directly for callers who don’t need the dispatch.</p>
</section><section id="time-dependent-discrimination-timeroc_survmat" class="level2"><h2 class="anchored" data-anchor-id="time-dependent-discrimination-timeroc_survmat">Time-dependent discrimination: <code>timeroc_survmat()</code>
</h2>
<p>The C-index and the Brier score summarize discrimination and calibration at a single horizon. <code><a href="https://rdrr.io/pkg/survalis/man/timeroc_survmat.html">timeroc_survmat()</a></code> adds a vectorized cumulative/dynamic AUC curve over a vector of evaluation times, matching <code>timeROC::timeROC(weighting = "marginal")</code> to about 1e-3 (Uno et al.&nbsp;2007 / Heagerty and Zheng 2005):</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">y</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survival/man/Surv.html">Surv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">veteran</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">time</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">veteran</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">status</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mod_rsf</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survalis/man/fit_rsf.html">fit_rsf</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survival/man/Surv.html">Surv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">time</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">status</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">age</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">karno</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">celltype</span>, data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">veteran</span>, ntree <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">sp_rsf</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survalis/man/predict_rsf.html">predict_rsf</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mod_rsf</span>, newdata <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">veteran</span>, times <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survalis/man/timeroc_survmat.html">timeroc_survmat</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">y</span>, predicted <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">sp_rsf</span>, times <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>  time      auc
1   30 0.886782
2   90 0.882384
3  180 0.897919</code></pre>
</div>
</div>
</section><section id="a-native-kaplan-meier-plot-plot_survcurve" class="level2"><h2 class="anchored" data-anchor-id="a-native-kaplan-meier-plot-plot_survcurve">A native Kaplan-Meier plot: <code>plot_survcurve()</code>
</h2>
<p><code><a href="https://rdrr.io/pkg/survalis/man/plot_survcurve.html">plot_survcurve()</a></code> adds a survminer-style Kaplan-Meier curve with a confidence ribbon, a log-rank p-value annotation, and an aligned number-at-risk table, built directly on <code><a href="https://rdrr.io/pkg/survalis/man/theme_survalis.html">theme_survalis()</a></code> / <code><a href="https://rdrr.io/pkg/survalis/man/survalis-scales.html">scale_color_survalis()</a></code> rather than depending on the survminer package. The risk table is composed with <code>patchwork</code>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survalis/man/plot_survcurve.html">plot_survcurve</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survival/man/Surv.html">Surv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">time</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">status</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">celltype</span>, data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">veteran</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure"><p><a href="index_files/figure-html/survcurve-plot-1.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1"><img src="https://elbadisyimad.com/blog/2026-08-18-survalis-cran-release/index_files/figure-html/survcurve-plot-1.png" class="img-fluid figure-img" width="672"></a></p>
</figure>
</div>
</div>
</div>
</section><section id="a-consistent-visual-system-theme_survalis-and-the-color-scales" class="level2"><h2 class="anchored" data-anchor-id="a-consistent-visual-system-theme_survalis-and-the-color-scales">A consistent visual system: <code>theme_survalis()</code> and the color scales</h2>
<p>Every plotting function used to call <code>theme_minimal()</code> with its own <code>base_size</code>, and grouped plots fell back to ggplot2’s default hue palette except for <code><a href="https://rdrr.io/pkg/survalis/man/plot_survcurve.html">plot_survcurve()</a></code>. <code><a href="https://rdrr.io/pkg/survalis/man/theme_survalis.html">theme_survalis()</a></code> and the colorblind-friendly <code><a href="https://rdrr.io/pkg/survalis/man/survalis-scales.html">scale_color_survalis()</a></code> / <code><a href="https://rdrr.io/pkg/survalis/man/survalis-scales.html">scale_fill_survalis()</a></code> (ColorBrewer “Dark2”-based, interpolated beyond 8 levels) were retrofitted across every plotting function, <code><a href="https://rdrr.io/pkg/survalis/man/plot_ale.html">plot_ale()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/plot_pdp.html">plot_pdp()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/plot_shap.html">plot_shap()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/plot_interactions.html">plot_interactions()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/plot_calibration.html">plot_calibration()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/plot_counterfactual.html">plot_counterfactual()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/plot_surrogate.html">plot_surrogate()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/plot_tree_surrogate.html">plot_tree_surrogate()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/plot_varimp.html">plot_varimp()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/plot_survmat.html">plot_survmat()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/plot_survmetalearner_weights.html">plot_survmetalearner_weights()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/plot_benchmark.html">plot_benchmark()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/cv_plot.html">cv_plot()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/plot_survcurve.html">plot_survcurve()</a></code>, so package figures read as one system instead of thirteen independent styles. Single-series hardcoded colors (<code>"steelblue"</code>, <code>"pink"</code>, <code>"tomato"</code>, ad-hoc green/red hex codes) were replaced the same way, and every plot that can show both positive and negative values now draws a dashed zero-reference line.</p>
<p>As of 0.9.0, every one of those functions also takes a <code>title</code> argument: pass a custom string, leave it out for the previous auto-generated title, or pass <code>title = NULL</code> to drop it entirely for journals that require caption-only figures.</p>
</section><section id="uncertainty-in-variable-importance-plot_varimp" class="level2"><h2 class="anchored" data-anchor-id="uncertainty-in-variable-importance-plot_varimp">Uncertainty in variable importance: <code>plot_varimp()</code>
</h2>
<p><code><a href="https://rdrr.io/pkg/survalis/man/compute_varimp.html">compute_varimp()</a></code> computes permutation-based importance by repeating a metric drop over <code>n_repetitions</code> permutations per feature. It used to summarize those repetitions down to a single point estimate and discard them. <code><a href="https://rdrr.io/pkg/survalis/man/plot_varimp.html">plot_varimp()</a></code> now draws the full per-repetition distribution as a boxplot instead of a lone point, and <code><a href="https://rdrr.io/pkg/survalis/man/compute_varimp.html">compute_varimp()</a></code> keeps the raw values as a <code>"raw_scores"</code> attribute so the plot can use them (falling back to the old point-plot for hand-built summary tables without that attribute):</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mod_cox</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survalis/man/fit_coxph.html">fit_coxph</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survival/man/Surv.html">Surv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">time</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">status</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">age</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">karno</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">celltype</span>, data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">veteran</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vi</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survalis/man/compute_varimp.html">compute_varimp</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mod_cox</span>, times <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span>, metric <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ibs"</span>, n_repetitions <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, seed <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">p</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survalis/man/plot_varimp.html">plot_varimp</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vi</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot2</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://ggplot2.tidyverse.org/reference/ggsave.html">ggsave</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"featured.png"</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">p</span>, width <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, height <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.5</span>, dpi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">150</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">p</span></span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure"><p><a href="index_files/figure-html/varimp-plot-1.png" class="lightbox" data-gallery="quarto-lightbox-gallery-2"><img src="https://elbadisyimad.com/blog/2026-08-18-survalis-cran-release/index_files/figure-html/varimp-plot-1.png" class="img-fluid figure-img" width="672"></a></p>
</figure>
</div>
</div>
</div>
</section><section id="migration-to-data.table" class="level2"><h2 class="anchored" data-anchor-id="migration-to-data.table">Migration to data.table</h2>
<p>Every internal data-manipulation path, the CV/metrics engine (<code><a href="https://rdrr.io/pkg/survalis/man/cv_survlearner.html">cv_survlearner()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/cv_summary.html">cv_summary()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/score_survmodel.html">score_survmodel()</a></code>), all nineteen <code>tune_*()</code> functions, <code><a href="https://rdrr.io/pkg/survalis/man/cv_survmetalearner.html">cv_survmetalearner()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/benchmark_tuned_survlearners.html">benchmark_tuned_survlearners()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/compute_shap.html">compute_shap()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/compute_calibration.html">compute_calibration()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/plot_survmat.html">plot_survmat()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/compute_varimp.html">compute_varimp()</a></code>, and the descriptive <code>list_*()</code> helpers, was migrated file by file from dplyr/tidyr/purrr/tibble to data.table. <code>dplyr</code>, <code>tidyr</code>, <code>purrr</code>, and <code>tibble</code> are no longer in <code>Imports</code> at all; data.table is now the sole data-manipulation engine. <code><a href="https://rdrr.io/pkg/survalis/man/cv_summary.html">cv_summary()</a></code>/<code><a href="https://rdrr.io/pkg/survalis/man/score_survmodel.html">score_survmodel()</a></code> and <code><a href="https://rdrr.io/pkg/survalis/man/summarise_benchmark.html">summarise_benchmark()</a></code> now round summary statistics to 3 decimals by default, consistently.</p>
</section><section id="corrections-along-the-way" class="level2"><h2 class="anchored" data-anchor-id="corrections-along-the-way">Corrections along the way</h2>
<p>A few of these were silent correctness bugs, not just style:</p>
<ul>
<li>
<strong><code><a href="https://rdrr.io/pkg/survalis/man/auc_survmat.html">auc_survmat()</a></code> case definition.</strong> Cases were defined as events with <code>time &lt;= t_star</code> instead of the canonical Uno/timeROC <code>time &lt; t_star</code>. This fed directly into the <code>"auc"</code> metric used throughout <code><a href="https://rdrr.io/pkg/survalis/man/score_survmodel.html">score_survmodel()</a></code>, <code>benchmark_*()</code>, and <code><a href="https://rdrr.io/pkg/survalis/man/fit_survmetalearner.html">fit_survmetalearner()</a></code>, so it was corrected everywhere at once.</li>
<li>
<strong>Silently dropped learners in nested tuning.</strong> <code><a href="https://rdrr.io/pkg/survalis/man/benchmark_tuned_survlearners.html">benchmark_tuned_survlearners()</a></code> selected tuning-result columns with <code>tuning_results[1, cols, drop = FALSE]</code>, relying on data.frame <code>[</code> semantics; data.table’s <code>[</code> doesn’t select columns from a variable the same way, so every fold for a data.table-migrated learner errored and the learner was quietly dropped with a warning. Fixed with a <code>.select_cols()</code> helper that works for both data.frame/tibble and data.table inputs.</li>
<li>
<strong><code>tune_survsvm(refit_best = TRUE)</code> crashes.</strong> A top-ranked grid candidate could fail to refit on the full dataset (a <code>quadprog</code> QP infeasibility that only shows up on certain BLAS backends, including CRAN’s OpenBLAS check machine). It now falls back to the next-best candidate and only errors if every candidate fails.</li>
<li>
<strong><code>plot_interactions(type = "heatmap")</code> readability.</strong> The <code>white -&gt; steelblue</code> gradient had too little contrast in the mid-range and the zero-valued diagonal blended into the low end. Switched to a perceptually uniform viridis scale, flipped afterward so high interaction values read as dark rather than bright, matching conventional heatmap reading.</li>
<li>
<strong><code><a href="https://rdrr.io/pkg/survalis/man/plot_pdp.html">plot_pdp()</a></code> per-time facets.</strong> Free y-axis scales made survival-probability panels visually incomparable across facets; now fixed to <code>[0, 1]</code> via <code>coord_cartesian()</code>.</li>
<li>
<strong>Stale generated docs breaking CI.</strong> Three <code>.Rd</code> files had hand-drifted out of sync with their roxygen source, using <code>\donttest{}</code> (which CI runs) instead of <code>\dontrun{}</code>, causing an example to fail on an undefined object. Regenerated from source and verified with <code>R CMD check --run-donttest</code>.</li>
</ul></section><section id="links" class="level2"><h2 class="anchored" data-anchor-id="links">Links</h2>
<ul>
<li><a href="https://CRAN.R-project.org/package=survalis">CRAN.R-project.org/package=survalis</a></li>
<li>GitHub: <a href="https://github.com/ielbadisy/survalis">github.com/ielbadisy/survalis</a>
</li>
</ul>
<hr>
<footer><a href="../../index.html#blog">Back to blog</a>
</footer>

</section><a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>R</category>
  <category>survival-analysis</category>
  <category>machine-learning</category>
  <category>packages</category>
  <guid>https://elbadisyimad.com/blog/2026-08-18-survalis-cran-release/</guid>
  <pubDate>Mon, 17 Aug 2026 23:00:00 GMT</pubDate>
  <media:content url="https://elbadisyimad.com/blog/2026-08-18-survalis-cran-release/featured.png" medium="image" type="image/png" height="93" width="144"/>
</item>
<item>
  <title>survalis: An Interpretable Survival Machine Learning Framework in R</title>
  <dc:creator>Imad El Badisy</dc:creator>
  <link>https://elbadisyimad.com/blog/2026-03-30-survalis/</link>
  <description><![CDATA[ <p>Comparing survival models in R usually means learning a different interface for each one: <code><a href="https://rdrr.io/pkg/survival/man/coxph.html">coxph()</a></code>, <code><a href="https://www.randomforestsrc.org//reference/rfsrc.html">randomForestSRC::rfsrc()</a></code>, <code><a href="https://rdrr.io/pkg/xgboost/man/xgb.train.html">xgboost::xgb.train()</a></code>, and a deep survival network all expect different data shapes and return different prediction objects. <strong>survalis</strong> was built to close that gap: a unified framework for survival machine learning with a consistent contract for fitting, prediction, evaluation, and interpretation.</p>
<section id="core-philosophy" class="level2"><h2 class="anchored" data-anchor-id="core-philosophy">Core philosophy</h2>
<p>Every learner in survalis follows the same pattern:</p>
<ul>
<li>
<code>fit_*()</code> functions return a standardized <code>mlsurv_model</code> object</li>
<li>
<code>predict_*()</code> functions return a <code>data.frame</code> of survival probabilities, one row per subject, one column per requested time (<code>t=100</code>, <code>t=200</code>, …)</li>
<li>Evaluation is fully modular: any <code>fit_*</code>/<code>predict_*</code> pair plugs into <code><a href="https://rdrr.io/pkg/survalis/man/cv_survlearner.html">cv_survlearner()</a></code> or <code><a href="https://rdrr.io/pkg/survalis/man/score_survmodel.html">score_survmodel()</a></code>
</li>
<li>Everything downstream (benchmarking, calibration, interpretation) is designed to work on that same survival-probability matrix, regardless of which learner produced it</li>
</ul></section><section id="why-explicit-fit_coxph-fit_rsf-instead-of-one-fitlearner-..." class="level2"><h2 class="anchored" data-anchor-id="why-explicit-fit_coxph-fit_rsf-instead-of-one-fitlearner-...">Why explicit <code>fit_coxph()</code> / <code>fit_rsf()</code> instead of one <code>fit(learner = ...)</code>
</h2>
<p>This is a deliberate departure from <code>funcml</code>, my general-purpose ML package, where <code>fit(y ~ ., data, learner = "ranger")</code> collapses every learner behind one verb and a string argument. survalis keeps a named function per learner, <code><a href="https://rdrr.io/pkg/survalis/man/fit_coxph.html">fit_coxph()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/fit_rsf.html">fit_rsf()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/fit_survdnn.html">fit_survdnn()</a></code>, and so on, instead of a single dispatcher.</p>
<p>The reason is that the survival setting is not just “regression with a different loss.” Every learner here already has to negotiate right-censoring, risk sets, and time-varying prediction targets on its own terms, and each one leans on a different underlying package (<code>survival</code>, <code>randomForestSRC</code>, <code>xgboost</code>, <code>torch</code>, <code>flexsurv</code>, …) with its own quirks around ties, time horizons, and baseline hazard estimation. Hiding <code>fit_coxph</code> and <code>fit_rsf</code> behind a shared <code>fit(learner = "rsf")</code> string would trade a small amount of typing for a layer of indirection between the call site and the model-specific machinery it actually invokes, machinery that, in survival analysis, is rarely interchangeable enough to be worth hiding. Keeping the learner name in the function name is a compactness choice: the API surface is larger (nineteen <code>fit_*()</code>/<code>predict_*()</code> pairs instead of one), but each call is self-describing and there is one fewer level of abstraction between what you write and what runs.</p>
<p>What survalis does unify is everything <em>after</em> fitting: <code>predict_*()</code> always returns the same survival-probability matrix shape, so <code><a href="https://rdrr.io/pkg/survalis/man/cindex_survmat.html">cindex_survmat()</a></code>, <code><a href="https://rdrr.io/pkg/survival/man/brier.html">brier()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/cv_survlearner.html">cv_survlearner()</a></code>, and <code><a href="https://rdrr.io/pkg/survalis/man/benchmark.html">benchmark()</a></code> never need to know which <code>fit_*()</code> produced it. The genericity lives at the evaluation/interpretation layer, not at the fitting layer.</p>
<p>That output shape was a deliberate constraint, not an incidental one. A Cox model naturally hands back a linear predictor or a hazard ratio; a random survival forest hands back an ensemble of terminal-node curves; a deep survival network hands back whatever its loss was trained on (a Cox partial likelihood, an AFT loss, a discrete-time hazard). <code><a href="https://rdrr.io/pkg/survalis/man/fit_survdnn.html">fit_survdnn()</a></code> itself can predict a linear predictor if asked, since its loss functions include a Cox-style formulation. survalis standardizes on the survival-probability matrix anyway, over times <code>t=100</code>, <code>t=200</code>, and so on, because a matrix is, by construction, a richer object than a scalar: a linear predictor collapses a subject’s entire risk trajectory into one number and one implicit ranking, while a survival curve preserves how that risk actually unfolds over the follow-up window, which is what a fixed-horizon metric, a time-varying AUC, or a calibration curve each need to read back out at a different point. Forcing every <code>predict_*()</code> to that one shape throws away learner-specific detail on the way out (a Cox model’s clean linear score, a forest’s raw ensemble votes), but it is exactly what makes <code><a href="https://rdrr.io/pkg/survalis/man/cindex_survmat.html">cindex_survmat()</a></code>, <code><a href="https://rdrr.io/pkg/survival/man/brier.html">brier()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/timeroc_survmat.html">timeroc_survmat()</a></code>, and every interpretation function in the package learner-agnostic, without asking any of them to reconstruct a survival curve from a scalar first. The alternative, keeping each learner’s native output format and writing metric functions that branch on model class, is the design survalis specifically avoids.</p>
</section><section id="nineteen-learners-one-interface" class="level2"><h2 class="anchored" data-anchor-id="nineteen-learners-one-interface">Nineteen learners, one interface</h2>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;"><a href="https://rdrr.io/r/base/library.html">library</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;"><a href="https://CRAN.R-project.org/package=survalis">survalis</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survalis/man/list_survlearners.html">list_survlearners</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>           learner                 fit                 predict             tune
1            coxph           fit_coxph           predict_coxph             &lt;NA&gt;
2            aalen           fit_aalen           predict_aalen             &lt;NA&gt;
3           glmnet          fit_glmnet          predict_glmnet      tune_glmnet
4        selectcox       fit_selectcox       predict_selectcox   tune_selectcox
5           aftgee          fit_aftgee          predict_aftgee             &lt;NA&gt;
6      flexsurvreg     fit_flexsurvreg     predict_flexsurvreg tune_flexsurvreg
7            stpm2           fit_stpm2           predict_stpm2             &lt;NA&gt;
8          bnnsurv         fit_bnnsurv         predict_bnnsurv     tune_bnnsurv
9            rpart           fit_rpart           predict_rpart       tune_rpart
10            bart            fit_bart            predict_bart        tune_bart
11         xgboost         fit_xgboost         predict_xgboost     tune_xgboost
12        coxboost        fit_coxboost        predict_coxboost    tune_coxboost
13         fastgbm         fit_fastgbm         predict_fastgbm             &lt;NA&gt;
14          ranger          fit_ranger          predict_ranger      tune_ranger
15             rsf             fit_rsf             predict_rsf         tune_rsf
16         cforest         fit_cforest         predict_cforest     tune_cforest
17      blackboost      fit_blackboost      predict_blackboost  tune_blackboost
18         survsvm         fit_survsvm         predict_survsvm     tune_survsvm
19         survdnn         fit_survdnn         predict_survdnn     tune_survdnn
20        densemlp        fit_densemlp        predict_densemlp             &lt;NA&gt;
21            orsf            fit_orsf            predict_orsf        tune_orsf
22          rpsurv          fit_rpsurv          predict_rpsurv             &lt;NA&gt;
23          nbsurv          fit_nbsurv          predict_nbsurv             &lt;NA&gt;
24 survmetalearner fit_survmetalearner predict_survmetalearner             &lt;NA&gt;
   has_fit has_predict has_tune available
1     TRUE        TRUE    FALSE      TRUE
2     TRUE        TRUE    FALSE      TRUE
3     TRUE        TRUE     TRUE      TRUE
4     TRUE        TRUE     TRUE      TRUE
5     TRUE        TRUE    FALSE      TRUE
6     TRUE        TRUE     TRUE      TRUE
7     TRUE        TRUE    FALSE      TRUE
8     TRUE        TRUE     TRUE      TRUE
9     TRUE        TRUE     TRUE      TRUE
10    TRUE        TRUE     TRUE      TRUE
11    TRUE        TRUE     TRUE      TRUE
12    TRUE        TRUE     TRUE      TRUE
13    TRUE        TRUE    FALSE      TRUE
14    TRUE        TRUE     TRUE      TRUE
15    TRUE        TRUE     TRUE      TRUE
16    TRUE        TRUE     TRUE      TRUE
17    TRUE        TRUE     TRUE      TRUE
18    TRUE        TRUE     TRUE      TRUE
19    TRUE        TRUE     TRUE      TRUE
20    TRUE        TRUE    FALSE      TRUE
21    TRUE        TRUE     TRUE      TRUE
22    TRUE        TRUE    FALSE      TRUE
23    TRUE        TRUE    FALSE      TRUE
24    TRUE        TRUE    FALSE      TRUE</code></pre>
</div>
</div>
<p>That list spans semiparametric (<code>coxph</code>, <code>aalen</code>), parametric (<code>flexsurvreg</code>, <code>stpm2</code>, <code>aftgee</code>), tree-based and ensemble (<code>rpart</code>, <code>rsf</code>, <code>cforest</code>, <code>orsf</code>), boosting (<code>xgboost</code>, <code>blackboost</code>), kernel (<code>survsvm</code>), and deep-learning (<code>survdnn</code>, <code>bnnsurv</code>) learners, plus <code>survmetalearner</code> for combining several of them. Most also ship a matching <code>tune_*()</code> function for grid or random hyperparameter search.</p>
</section><section id="a-minimal-example" class="level2"><h2 class="anchored" data-anchor-id="a-minimal-example">A minimal example</h2>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;"><a href="https://rdrr.io/r/base/library.html">library</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;"><a href="https://github.com/therneau/survival">survival</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">270</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mod</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survalis/man/fit_coxph.html">fit_coxph</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survival/man/Surv.html">Surv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">time</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">status</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">age</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">karno</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">celltype</span>, data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">veteran</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">sp</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survalis/man/predict_coxph.html">predict_coxph</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mod</span>, newdata <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">veteran</span>, times <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/utils/head.html">head</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">sp</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>       t=90      t=180       t=270
1 0.6640601 0.37822072 0.257579996
2 0.7361432 0.48310054 0.362410259
3 0.6104309 0.30966354 0.194867900
4 0.6541127 0.36490330 0.245015675
5 0.7375010 0.48521958 0.364629899
6 0.1897037 0.01929484 0.004055248</code></pre>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times_fine</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/seq.html">seq</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>, by <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">sp_fine</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survalis/man/predict_coxph.html">predict_coxph</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mod</span>, newdata <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">veteran</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span>, times <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times_fine</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">p</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survalis/man/plot_survmat.html">plot_survmat</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">sp_fine</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot2</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://ggplot2.tidyverse.org/reference/ggsave.html">ggsave</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"featured.png"</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">p</span>, width <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, height <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.5</span>, dpi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">150</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">p</span></span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure"><p><a href="index_files/figure-html/survmat-plot-1.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1"><img src="https://elbadisyimad.com/blog/2026-03-30-survalis/index_files/figure-html/survmat-plot-1.png" class="img-fluid figure-img" width="672"></a></p>
</figure>
</div>
</div>
</div>
<p>Discrimination and calibration are single function calls away, at a fixed horizon or cross-validated across folds:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">y</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survival/man/Surv.html">Surv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">veteran</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">time</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">veteran</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">status</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span></span>
<span>  cindex <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survalis/man/cindex_survmat.html">cindex_survmat</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">y</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">sp</span>, t_star <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>,</span>
<span>  brier  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">survalis</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survalis/man/brier.html">brier</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">y</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">sp</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[[</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"t=180"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span>, t_star <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>cindex.C index    brier.brier 
      0.733744       0.134603 </code></pre>
</div>
</div>
<p>Swap <code>fit_coxph</code>/<code>predict_coxph</code> for any other pair in <code><a href="https://rdrr.io/pkg/survalis/man/list_survlearners.html">list_survlearners()</a></code> and every downstream call, <code><a href="https://rdrr.io/pkg/survalis/man/cindex_survmat.html">cindex_survmat()</a></code>, <code><a href="https://rdrr.io/pkg/survival/man/brier.html">brier()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/cv_survlearner.html">cv_survlearner()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/benchmark.html">benchmark()</a></code>, stays exactly the same.</p>
</section><section id="beyond-prediction-interpretation" class="level2"><h2 class="anchored" data-anchor-id="beyond-prediction-interpretation">Beyond prediction: interpretation</h2>
<p>Because every learner returns the same survival-probability shape, survalis’s interpretability layer works uniformly across all of them: permutation variable importance (<code><a href="https://rdrr.io/pkg/survalis/man/compute_varimp.html">compute_varimp()</a></code>), accumulated local effects and partial dependence (<code><a href="https://rdrr.io/pkg/survalis/man/compute_ale.html">compute_ale()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/compute_pdp.html">compute_pdp()</a></code>), SHAP-based attribution (<code><a href="https://rdrr.io/pkg/survalis/man/compute_shap.html">compute_shap()</a></code>), pairwise interaction strength (<code><a href="https://rdrr.io/pkg/survalis/man/compute_interactions.html">compute_interactions()</a></code>), counterfactual recommendations (<code><a href="https://rdrr.io/pkg/survalis/man/compute_counterfactual.html">compute_counterfactual()</a></code>), and surrogate-tree explanations (<code><a href="https://rdrr.io/pkg/survalis/man/compute_surrogate.html">compute_surrogate()</a></code>, <code><a href="https://rdrr.io/pkg/survalis/man/compute_tree_surrogate.html">compute_tree_surrogate()</a></code>), each with a matching <code>plot_*()</code> function.</p>
</section><section id="install" class="level2"><h2 class="anchored" data-anchor-id="install">Install</h2>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/utils/install.packages.html">install.packages</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"survalis"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
</section><section id="links" class="level2"><h2 class="anchored" data-anchor-id="links">Links</h2>
<ul>
<li><a href="https://CRAN.R-project.org/package=survalis">CRAN.R-project.org/package=survalis</a></li>
<li>GitHub: <a href="https://github.com/ielbadisy/survalis">github.com/ielbadisy/survalis</a>
</li>
</ul>
<hr>
<footer><a href="../../index.html#blog">Back to blog</a>
</footer>

</section><a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>R</category>
  <category>survival-analysis</category>
  <category>machine-learning</category>
  <category>packages</category>
  <guid>https://elbadisyimad.com/blog/2026-03-30-survalis/</guid>
  <pubDate>Sun, 29 Mar 2026 23:00:00 GMT</pubDate>
  <media:content url="https://elbadisyimad.com/blog/2026-03-30-survalis/featured.png" medium="image" type="image/png" height="93" width="144"/>
</item>
<item>
  <title>unsurv: Unsupervised Clustering of Individualized Survival Curves</title>
  <dc:creator>Imad El Badisy</dc:creator>
  <link>https://elbadisyimad.com/blog/2025-12-01-unsurv/</link>
  <description><![CDATA[ <p>Survival analysis typically ends at the population level: a single estimated curve, or a hazard ratio summarizing the average effect of a covariate. But individualized survival curves, one per patient, open a richer question: <strong>can we identify subgroups of patients with similar prognosis trajectories, without ever labeling anyone in advance?</strong></p>
<p><strong>unsurv</strong> answers that question. It clusters individualized survival curves using Partitioning Around Medoids (PAM), with principled preprocessing choices (monotonic enforcement, weighted distances, automatic K selection) and a clean set of plotting helpers.</p>
<section id="what-is-unsurv" class="level2"><h2 class="anchored" data-anchor-id="what-is-unsurv">What is unsurv?</h2>
<p><code>unsurv</code> (v0.6.0) takes a matrix of survival probabilities (rows are subjects, columns are time points) and returns cluster assignments, medoid curves, and a silhouette diagnostic.</p>
<p>Install:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/utils/install.packages.html">install.packages</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"unsurv"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
</section><section id="the-core-idea" class="level2"><h2 class="anchored" data-anchor-id="the-core-idea">The core idea</h2>
<p>Suppose you have estimated individual survival curves <img src="https://latex.codecogs.com/png.latex?S_i(t_1),%20%5Cldots,%20S_i(t_m)"> for <img src="https://latex.codecogs.com/png.latex?n"> patients on a shared time grid <img src="https://latex.codecogs.com/png.latex?t_1%20%3C%20%5Ccdots%20%3C%20t_m"> (from any model: Kaplan–Meier stratified by covariates, a Cox model, a random survival forest, or <code>survdnn</code>). Stack them into an <img src="https://latex.codecogs.com/png.latex?n%20%5Ctimes%20m"> matrix <img src="https://latex.codecogs.com/png.latex?%5Cmathbf%7BS%7D"> and pass it to <code><a href="https://rdrr.io/pkg/unsurv/man/unsurv.html">unsurv()</a></code>.</p>
<p>The algorithm:</p>
<ol type="1">
<li>Optionally enforce monotone non-increasing curves.</li>
<li>Optionally smooth curves with a median filter.</li>
<li>Compute a weighted distance matrix (<img src="https://latex.codecogs.com/png.latex?L_1"> or <img src="https://latex.codecogs.com/png.latex?L_2">) using trapezoidal weights by default, so time points in regions of faster change contribute more.</li>
<li>Run PAM on the distance matrix.</li>
<li>If <img src="https://latex.codecogs.com/png.latex?K"> is unspecified, select the <img src="https://latex.codecogs.com/png.latex?K%20%5Cin%20%5C%7B2,%20%5Cldots,%20K_%5Ctext%7Bmax%7D%5C%7D"> that maximizes mean silhouette width.</li>
</ol></section><section id="basic-usage" class="level2"><h2 class="anchored" data-anchor-id="basic-usage">Basic usage</h2>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;"><a href="https://rdrr.io/r/base/library.html">library</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;"><a href="https://CRAN.R-project.org/package=unsurv">unsurv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Simulate survival curves from two latent risk groups</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/Random.html">set.seed</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">n</span>     <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/seq.html">seq</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, length.out <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">grp</span>   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/sample.html">sample</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">n</span>, replace <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">rates</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/ifelse.html">ifelse</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">grp</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">S</span>     <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/outer.html">outer</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">rates</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span>, <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">r</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">t</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/Log.html">exp</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">r</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">t</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">S</span>     <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">S</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/matrix.html">matrix</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/stats/Normal.html">rnorm</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">n</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/length.html">length</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>, sd <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.02</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>, nrow <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">n</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Cluster with automatic K selection</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/unsurv/man/unsurv.html">unsurv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">S</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span>, K <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>, K_max <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, seed <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">K</span>               <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># selected number of clusters</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 2</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/table.html">table</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">clusters</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># cluster assignment per subject</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>
 1  2 
44 56 </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">silhouette_mean</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># mean silhouette width at the selected K</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 0.9393843</code></pre>
</div>
</div>
</section><section id="distance-and-weighting-options" class="level2"><h2 class="anchored" data-anchor-id="distance-and-weighting-options">Distance and weighting options</h2>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># L1 (Manhattan) distance: more robust to outlier curves</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit_l1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/unsurv/man/unsurv.html">unsurv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">S</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span>, K <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, distance <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"L1"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Custom time weights: emphasize early time points</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">w</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/rev.html">rev</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/seq.html">seq_along</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit_w</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/unsurv/man/unsurv.html">unsurv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">S</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span>, K <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, weights <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">w</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/sum.html">sum</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">w</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
</div>
</section><section id="monotonic-enforcement-and-smoothing" class="level2"><h2 class="anchored" data-anchor-id="monotonic-enforcement-and-smoothing">Monotonic enforcement and smoothing</h2>
<p>Raw predicted survival curves from flexible models may not be strictly non-increasing. <code>unsurv</code> corrects this before clustering:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/unsurv/man/unsurv.html">unsurv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span></span>
<span>  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">S</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span>, K <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>, K_max <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, seed <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>,</span>
<span>  enforce_monotone   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>,  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># project each curve to isotonic</span></span>
<span>  smooth_median_width <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># median filter of width 5 over time</span></span>
<span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
</div>
</section><section id="predicting-clusters-for-new-subjects" class="level2"><h2 class="anchored" data-anchor-id="predicting-clusters-for-new-subjects">Predicting clusters for new subjects</h2>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># newdata: n_new x m matrix of survival curves for new patients</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pred</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/stats/predict.html">predict</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit</span>, newdata <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">S</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pred</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 1 1 1 1 2</code></pre>
</div>
</div>
</section><section id="plotting" class="level2"><h2 class="anchored" data-anchor-id="plotting">Plotting</h2>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/graphics/plot.default.html">plot</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure"><p><a href="index_files/figure-html/medoids-plot-1.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1"><img src="https://elbadisyimad.com/blog/2025-12-01-unsurv/index_files/figure-html/medoids-plot-1.png" class="img-fluid figure-img" width="672"></a></p>
</figure>
</div>
</div>
</div>
</section><section id="combining-with-a-survival-model" class="level2"><h2 class="anchored" data-anchor-id="combining-with-a-survival-model">Combining with a survival model</h2>
<p>A natural pipeline is:</p>
<ol type="1">
<li>Fit individualized survival curves with a model of your choice (e.g., <code>survdnn</code>, <code>rfsrc</code>, Cox with spline terms).</li>
<li>Predict <img src="https://latex.codecogs.com/png.latex?%5Chat%7BS%7D_i(t)"> on a common time grid.</li>
<li>Pass the resulting matrix to <code><a href="https://rdrr.io/pkg/unsurv/man/unsurv.html">unsurv()</a></code> to discover prognostic subgroups.</li>
<li>Use cluster membership as a stratification variable or as a phenotype to interrogate.</li>
</ol>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;"><a href="https://rdrr.io/r/base/library.html">library</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;"><a href="https://github.com/therneau/survival">survival</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;"><a href="https://rdrr.io/r/base/library.html">library</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;"><a href="https://CRAN.R-project.org/package=survdnn">survdnn</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">torch</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://torch.mlverse.org/docs/reference/torch_manual_seed.html">torch_manual_seed</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">dnn_fit</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survdnn/man/survdnn.html">survdnn</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survival/man/Surv.html">Surv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">time</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">status</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">age</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">sex</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ph.ecog</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ph.karno</span>, data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">lung</span>,</span>
<span>                   hidden <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">64</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">32</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>, loss <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cox"</span>, epochs <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, verbose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times_grid</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/seq.html">seq</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>, by <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">25</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">S_hat</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/matrix.html">as.matrix</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/stats/predict.html">predict</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">dnn_fit</span>, newdata <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">lung</span>, type <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"survival"</span>, times <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times_grid</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">clust</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/unsurv/man/unsurv.html">unsurv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">S_hat</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times_grid</span>, K <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>, K_max <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, seed <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/table.html">table</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">clust</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">clusters</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>
  1   2   3 
113  70  43 </code></pre>
</div>
</div>
</section><section id="methodological-background" class="level2"><h2 class="anchored" data-anchor-id="methodological-background">Methodological background</h2>
<p><code>unsurv</code>’s preprocessing choices, distance weighting, medoid-based clustering, and stability assessment are described in El Badisy (2026), <em>“unsurv: Clustering Individualized Survival Curves”</em>, Bioinformatics Advances, <a href="https://doi.org/10.1093/bioadv/vbag218">doi:10.1093/bioadv/vbag218</a>, with a demonstration on the METABRIC breast cancer cohort using <code>survdnn</code>-predicted curves.</p>
</section><section id="links" class="level2"><h2 class="anchored" data-anchor-id="links">Links</h2>
<ul>
<li>GitHub: <a href="https://github.com/ielbadisy/unsurv">github.com/ielbadisy/unsurv</a>
</li>
<li>Paper: <a href="https://doi.org/10.1093/bioadv/vbag218">doi:10.1093/bioadv/vbag218</a>
</li>
</ul>
<hr>
<footer><a href="../../index.html#blog">Back to blog</a>
</footer>

</section><a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>R</category>
  <category>survival-analysis</category>
  <category>clustering</category>
  <category>packages</category>
  <guid>https://elbadisyimad.com/blog/2025-12-01-unsurv/</guid>
  <pubDate>Sun, 30 Nov 2025 23:00:00 GMT</pubDate>
  <media:content url="https://elbadisyimad.com/blog/2025-12-01-unsurv/featured.png" medium="image" type="image/png" height="65" width="144"/>
</item>
<item>
  <title>survdnn: Deep Neural Networks for Survival Analysis in R</title>
  <dc:creator>Imad El Badisy</dc:creator>
  <link>https://elbadisyimad.com/blog/2025-10-01-survdnn/</link>
  <description><![CDATA[ <p>Survival analysis has traditionally been dominated by the Cox proportional hazards model and its semi-parametric extensions. Deep learning offers an alternative: one that can capture non-linear covariate effects and complex interactions without manual feature engineering. <strong>survdnn</strong> brings that capability to R via the <code>torch</code> backend, with the same formula-based interface that R users already know.</p>
<section id="what-is-survdnn" class="level2"><h2 class="anchored" data-anchor-id="what-is-survdnn">What is survdnn?</h2>
<p><code>survdnn</code> (v0.7.6) trains multilayer perceptrons for right-censored survival data. It supports four loss functions, built-in cross-validation, hyperparameter tuning, survival curve prediction, and standard evaluation metrics.</p>
<p>Install:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/utils/install.packages.html">install.packages</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"torch"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># backend</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/utils/install.packages.html">install.packages</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"survdnn"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
</section><section id="fitting-a-model" class="level2"><h2 class="anchored" data-anchor-id="fitting-a-model">Fitting a model</h2>
<p>The entry point is <code><a href="https://rdrr.io/pkg/survdnn/man/survdnn.html">survdnn()</a></code>, which takes a <code><a href="https://rdrr.io/pkg/survival/man/Surv.html">Surv()</a></code> formula:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;"><a href="https://rdrr.io/r/base/library.html">library</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;"><a href="https://github.com/therneau/survival">survival</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;"><a href="https://rdrr.io/r/base/library.html">library</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;"><a href="https://CRAN.R-project.org/package=survdnn">survdnn</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">torch</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://torch.mlverse.org/docs/reference/torch_manual_seed.html">torch_manual_seed</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survdnn/man/survdnn.html">survdnn</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span></span>
<span>  formula   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survival/man/Surv.html">Surv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">time</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">status</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">age</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">sex</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ph.ecog</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ph.karno</span>,</span>
<span>  data      <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">lung</span>,</span>
<span>  hidden    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">64</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">32</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>,</span>
<span>  activation <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"relu"</span>,</span>
<span>  loss      <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cox"</span>,</span>
<span>  epochs    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>,</span>
<span>  lr        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-3</span>,</span>
<span>  dropout   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>,</span>
<span>  batch_norm <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>,</span>
<span>  verbose   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span></span>
<span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit</span></span></code></pre></div></div>
</div>
</section><section id="loss-functions" class="level2"><h2 class="anchored" data-anchor-id="loss-functions">Loss functions</h2>
<p>Four loss functions are available, covering the major families of deep survival models:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead><tr class="header">
<th>Loss</th>
<th>Model family</th>
<th>When to use</th>
</tr></thead>
<tbody>
<tr class="odd">
<td><code>"cox"</code></td>
<td>Breslow Cox partial likelihood</td>
<td>Standard proportional hazards assumption</td>
</tr>
<tr class="even">
<td><code>"cox_l2"</code></td>
<td>L2-penalized Cox</td>
<td>Regularization for wide feature sets</td>
</tr>
<tr class="odd">
<td><code>"aft"</code></td>
<td>Accelerated failure time</td>
<td>Log-linear relationship preferred</td>
</tr>
<tr class="even">
<td><code>"coxtime"</code></td>
<td>CoxTime (Kvamme et al., JMLR 2019)</td>
<td>Time-varying covariate effects</td>
</tr>
</tbody>
</table></section><section id="prediction-and-survival-curves" class="level2"><h2 class="anchored" data-anchor-id="prediction-and-survival-curves">Prediction and survival curves</h2>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># predict linear predictor (risk score)</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/utils/head.html">head</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/stats/predict.html">predict</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit</span>, newdata <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">lung</span>, type <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lp"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1]  0.1397203 -0.2062566 -0.9678885  0.1454131 -0.7345585 -1.1179752</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># predict survival curves on a time grid</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/seq.html">seq</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>, by <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">surv</span>  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/stats/predict.html">predict</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit</span>, newdata <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">lung</span>, type <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"survival"</span>, times <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/utils/head.html">head</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">surv</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>        t=0      t=50     t=100     t=150     t=200     t=250     t=300
1 0.9951746 0.9361534 0.8451717 0.7604267 0.6144562 0.5117045 0.4266991
2 0.9965835 0.9543929 0.8877925 0.8238434 0.7085186 0.6224762 0.5473946
3 0.9984034 0.9784408 0.9459462 0.9134979 0.8513897 0.8014476 0.7547645
4 0.9951471 0.9358008 0.8443605 0.7592386 0.6127502 0.5097510 0.4246295
5 0.9979842 0.9728526 0.9322323 0.8920343 0.8161431 0.7561600 0.7009718
6 0.9986257 0.9814173 0.9533005 0.9250892 0.8706953 0.8265549 0.7849473
      t=350     t=400     t=450     t=500     t=550      t=600      t=650
1 0.3291391 0.2446004 0.1935003 0.1582133 0.1135787 0.08159666 0.05483936
2 0.4555458 0.3692460 0.3128289 0.2712947 0.2145830 0.16981532 0.12819513
3 0.6927352 0.6280267 0.5812417 0.5438405 0.4874379 0.43699172 0.38323199
4 0.3270575 0.2426419 0.1916944 0.1565566 0.1121769 0.08043761 0.05393788
5 0.6290261 0.5557598 0.5039996 0.4633978 0.4035571 0.35155256 0.29784911
6 0.7290997 0.6700901 0.6268990 0.5920222 0.5387818 0.49043253 0.43803954
       t=700      t=750       t=800       t=850       t=900       t=950
1 0.03171439 0.01237621 0.007940308 0.004207006 0.001865832 0.001865832
2 0.08701532 0.04471476 0.032664382 0.020839752 0.011723673 0.011723673
3 0.31981080 0.23436366 0.202402368 0.164090863 0.125440661 0.125440661
4 0.03109568 0.01206975 0.007724095 0.004077636 0.001800081 0.001800081
5 0.23701727 0.16006584 0.133011865 0.102049314 0.072695858 0.072695858
6 0.37488195 0.28688417 0.252875078 0.211093807 0.167527461 0.167527461
       t=1000
1 0.001865832
2 0.011723673
3 0.125440661
4 0.001800081
5 0.072695858
6 0.167527461</code></pre>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">p</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/graphics/plot.default.html">plot</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit</span>, newdata <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">lung</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span>, times <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">times</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot2</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://ggplot2.tidyverse.org/reference/ggsave.html">ggsave</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"featured.png"</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">p</span>, width <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, height <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">4.5</span>, dpi <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">150</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">p</span></span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure"><p><a href="index_files/figure-html/survcurve-plot-1.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1"><img src="https://elbadisyimad.com/blog/2025-10-01-survdnn/index_files/figure-html/survcurve-plot-1.png" class="img-fluid figure-img" width="672"></a></p>
</figure>
</div>
</div>
</div>
</section><section id="evaluation" class="level2"><h2 class="anchored" data-anchor-id="evaluation">Evaluation</h2>
<p><code><a href="https://rdrr.io/pkg/survdnn/man/evaluate_survdnn.html">evaluate_survdnn()</a></code> computes the concordance index and integrated Brier score from the fitted model:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survdnn/man/evaluate_survdnn.html">evaluate_survdnn</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit</span>, metrics <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cindex"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ibs"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>, times <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/seq.html">seq</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">800</span>, by <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>, newdata <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">lung</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># A tibble: 2 × 2
  metric value
  &lt;chr&gt;  &lt;dbl&gt;
1 cindex 0.689
2 ibs    0.162</code></pre>
</div>
</div>
</section><section id="hyperparameter-tuning-with-cross-validation" class="level2"><h2 class="anchored" data-anchor-id="hyperparameter-tuning-with-cross-validation">Hyperparameter tuning with cross-validation</h2>
<p><code><a href="https://rdrr.io/pkg/survdnn/man/tune_survdnn.html">tune_survdnn()</a></code> runs a grid search over the hyperparameter space with K-fold cross-validation. <code>param_grid</code> is a named list crossed via <code><a href="https://tidyr.tidyverse.org/reference/expand.html">tidyr::crossing()</a></code>, and must include <code>hidden</code>, <code>lr</code>, <code>activation</code>, <code>epochs</code>, <code>.loss_fn</code>, and <code>loss_name</code>:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">grid</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/list.html">list</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span></span>
<span>  hidden     <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/list.html">list</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">32</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>,</span>
<span>  lr         <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-3</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-4</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>,</span>
<span>  activation <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"relu"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>,</span>
<span>  epochs     <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>,</span>
<span>  .loss_fn   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/list.html">list</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cox_loss</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">aft_loss</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>,</span>
<span>  loss_name  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cox"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"aft"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">tuned</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survdnn/man/tune_survdnn.html">tune_survdnn</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span></span>
<span>  formula <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/survival/man/Surv.html">Surv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">time</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">status</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">age</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">sex</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ph.ecog</span>,</span>
<span>  data    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">lung</span>,</span>
<span>  times   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>,</span>
<span>  metrics <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"cindex"</span>,</span>
<span>  param_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">grid</span>,</span>
<span>  folds   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>,</span>
<span>  return  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"summary"</span></span>
<span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
</section><section id="architecture" class="level2"><h2 class="anchored" data-anchor-id="architecture">Architecture</h2>
<p>Under the hood, <code><a href="https://rdrr.io/pkg/survdnn/man/survdnn.html">survdnn()</a></code> builds an MLP via <code><a href="https://rdrr.io/pkg/survdnn/man/build_dnn.html">build_dnn()</a></code>: linear layers with optional batch normalization and dropout between each hidden layer, terminating in a single linear output. The <code>torch</code> optimizer (Adam by default) is configurable via <code>optimizer</code> and <code>optim_args</code>.</p>
</section><section id="methodological-background" class="level2"><h2 class="anchored" data-anchor-id="methodological-background">Methodological background</h2>
<p><code>survdnn</code>’s design, loss functions, and benchmarks against classical and machine learning survival models are described in El Badisy (2026), <em>“SurvDNN: Survival Deep Learning Models for Tabular Data”</em>, The R Journal, <a href="https://rjournal.github.io/articles/RJ-2026-008/">RJ-2026-008</a>.</p>
</section><section id="links" class="level2"><h2 class="anchored" data-anchor-id="links">Links</h2>
<ul>
<li>GitHub: <a href="https://github.com/ielbadisy/survdnn">github.com/ielbadisy/survdnn</a>
</li>
<li>Paper: <a href="https://rjournal.github.io/articles/RJ-2026-008/">RJ-2026-008</a>
</li>
</ul>
<hr>
<footer><a href="../../index.html#blog">Back to blog</a>
</footer>

</section><a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>R</category>
  <category>survival-analysis</category>
  <category>deep-learning</category>
  <category>packages</category>
  <guid>https://elbadisyimad.com/blog/2025-10-01-survdnn/</guid>
  <pubDate>Tue, 30 Sep 2025 23:00:00 GMT</pubDate>
  <media:content url="https://elbadisyimad.com/blog/2025-10-01-survdnn/featured.png" medium="image" type="image/png" height="93" width="144"/>
</item>
<item>
  <title>mimar: Compact Multiple Imputation, Assessment, and Reporting in R</title>
  <dc:creator>Imad El Badisy</dc:creator>
  <link>https://elbadisyimad.com/blog/2025-08-15-mimar/</link>
  <description><![CDATA[ <p>Missing data is the rule, not the exception, in health research. Yet most workflows still string together three or four packages: one to characterize missingness, one to impute, one to pool, one to evaluate, with no consistent API across them. <strong>mimar</strong> brings all of that under one roof.</p>
<section id="what-is-mimar" class="level2"><h2 class="anchored" data-anchor-id="what-is-mimar">What is mimar?</h2>
<p><code>mimar</code> (v0.8.0) covers the full missing-data analysis cycle:</p>
<ol type="1">
<li>
<strong>Amputation</strong>: artificially introduce missingness into a complete dataset for simulation studies</li>
<li>
<strong>Imputation</strong>: single or multiple imputation via chained equations with a choice of statistical or ML imputers</li>
<li>
<strong>Evaluation</strong>: diagnostic metrics comparing imputed distributions to observed and (when known) true values</li>
<li>
<strong>Pooling</strong>: Rubin’s rules applied to post-imputation model estimates</li>
</ol>
<p>Install:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/utils/install.packages.html">install.packages</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mimar"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
</section><section id="artificial-amputation" class="level2"><h2 class="anchored" data-anchor-id="artificial-amputation">Artificial amputation</h2>
<p><code><a href="https://rdrr.io/pkg/mimar/man/ampute.html">ampute()</a></code> introduces controlled missingness into a complete data frame, specifying the mechanism (MCAR, MAR, MNAR) and the proportion of missing cells:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;"><a href="https://rdrr.io/r/base/library.html">library</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;"><a href="https://CRAN.R-project.org/package=mimar">mimar</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/Random.html">set.seed</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">amp</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/mimar/man/ampute.html">ampute</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">iris</span>, prop <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, mechanism <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MCAR"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/utils/head.html">head</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">amp</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">data</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>       <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># the amputed data frame</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># basetable: 6 x 5
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0           NA         0.2  setosa
3          4.7         3.2          1.3         0.2    &lt;NA&gt;
4          4.6         3.1          1.5          NA  setosa
5           NA         3.6          1.4          NA  setosa
6          5.4          NA          1.7         0.4  setosa</code></pre>
</div>
</div>
</section><section id="multiple-imputation" class="level2"><h2 class="anchored" data-anchor-id="multiple-imputation">Multiple imputation</h2>
<p><code><a href="https://rdrr.io/pkg/mimar/man/impute.html">impute()</a></code> runs chained equations with any registered imputer. The default is predictive mean matching (<code>"pmm"</code>), but ML-based imputers are equally accessible:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># PMM: the safe default</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">imp_pmm</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/mimar/man/impute.html">impute</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">amp</span>, m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, imputer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pmm"</span>, maxit <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Random forest imputation</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">imp_rf</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/mimar/man/impute.html">impute</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">amp</span>, m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, imputer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ranger"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># XGBoost imputation</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">imp_xgb</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/mimar/man/impute.html">impute</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">amp</span>, m <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, imputer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"xgboost"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/class.html">class</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">imp_pmm</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "mimar_imputation" "list"            </code></pre>
</div>
</div>
<p><code><a href="https://rdrr.io/pkg/mimar/man/impute.html">impute()</a></code> returns a <code>mimar_imputation</code> object containing all <code>m</code> completed datasets alongside metadata for downstream steps.</p>
</section><section id="available-imputers" class="level2"><h2 class="anchored" data-anchor-id="available-imputers">Available imputers</h2>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/mimar/man/imputer_registry.html">imputer_registry</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"imputer"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"implementation"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"stochastic"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># basetable: 25 x 3
   imputer implementation stochastic
1     mean          mimar      FALSE
2   median          mimar      FALSE
3     mode          mimar      FALSE
4    naive          mimar      FALSE
5     norm          mimar       TRUE
6      pmm          mimar       TRUE
7     spmm          mimar       TRUE
8   logreg          mimar       TRUE
9  polyreg          mimar       TRUE
10      rf        wrapped       TRUE
# 15 more rows</code></pre>
</div>
</div>
</section><section id="evaluation" class="level2"><h2 class="anchored" data-anchor-id="evaluation">Evaluation</h2>
<p>When the true values are known (after amputation, or from a simulation), <code><a href="https://rdrr.io/pkg/mimar/man/evaluate.html">evaluate()</a></code> computes recovery metrics comparing imputed to true values:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">diag</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/mimar/man/evaluate.html">evaluate</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">imp_pmm</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">diag</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">distribution</span>       <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># observed vs. imputed means, SDs, unique counts</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># basetable: 5 x 9
      variable    type missing observed_unique imputed_unique observed_mean
1 Sepal.Length numeric      33              33             28      5.837607
2  Sepal.Width numeric      39              22             19      3.075676
3 Petal.Length numeric      34              42             38      3.755172
4  Petal.Width numeric      34              21             21      1.252586
5      Species  factor      31               3              3            NA
  imputed_mean observed_sd imputed_sd
1     5.987273   0.8377645  0.7791618
2     3.035385   0.4509014  0.4011957
3     3.770000   1.8037808  1.5557433
4     1.076471   0.7519784  0.7701759
5           NA          NA         NA</code></pre>
</div>
</div>
</section><section id="completing-and-pooling" class="level2"><h2 class="anchored" data-anchor-id="completing-and-pooling">Completing and pooling</h2>
<p>Extract a single completed dataset or pool regression estimates across all <code>m</code> imputations using Rubin’s rules:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">completed</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/mimar/man/complete.html">complete</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">imp_pmm</span>, which <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/utils/head.html">head</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">completed</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code># basetable: 6 x 5
  Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
1          5.1         3.5          1.4         0.2     setosa
2          4.9         3.0          1.4         0.2     setosa
3          4.7         3.2          1.3         0.2 versicolor
4          4.6         3.1          1.5         0.2     setosa
5          5.1         3.6          1.4         0.5     setosa
6          5.4         3.3          1.7         0.4     setosa</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># fit a model on each completed dataset, then pool the coefficients</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">completed_list</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/lapply.html">lapply</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/seq.html">seq_len</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">imp_pmm</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">m</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>, <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">k</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/mimar/man/complete.html">complete</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">imp_pmm</span>, which <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">k</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fits</span>  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/lapply.html">lapply</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">completed_list</span>, <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">d</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/stats/lm.html">lm</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">Sepal.Length</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">Sepal.Width</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">Petal.Length</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">Petal.Width</span>, data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">d</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">betas</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/lapply.html">lapply</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fits</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">coef</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vars</span>  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/lapply.html">lapply</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fits</span>, <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">f</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/diag.html">diag</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/stats/vcov.html">vcov</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">f</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/mimar/man/pool.html">pool</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">betas</span>, variance <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vars</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>mimar pooled results
# basetable: 4 x 14
          term   estimate  std.error statistic  df      p.value   conf.low
1  (Intercept)  2.1204880 0.23942658  8.856527 Inf 8.254583e-19  1.6512205
2  Sepal.Width  0.5861945 0.06375298  9.194779 Inf 3.757668e-20  0.4612410
3 Petal.Length  0.7034397 0.05719104 12.299822 Inf 9.077385e-35  0.5913473
4  Petal.Width -0.5639728 0.12879778 -4.378746 Inf 1.193641e-05 -0.8164118
   conf.high m within_variance between_variance total_variance
1  2.5897555 5     0.057325087                0    0.057325087
2  0.7111480 5     0.004064442                0    0.004064442
3  0.8155320 5     0.003270815                0    0.003270815
4 -0.3115338 5     0.016588867                0    0.016588867
  relative_increase_variance  rule
1                          0 rubin
2                          0 rubin
3                          0 rubin
4                          0 rubin</code></pre>
</div>
</div>
</section><section id="when-to-use-mimar" class="level2"><h2 class="anchored" data-anchor-id="when-to-use-mimar">When to use mimar</h2>
<p><code>mimar</code> is designed for:</p>
<ul>
<li>
<strong>Simulation studies</strong>: amputate, impute, evaluate recovery under controlled conditions</li>
<li>
<strong>Applied health research</strong>: handle missing covariates or outcomes before regression or survival analysis</li>
<li>
<strong>ML-driven imputation</strong>: when the imputation model is complex enough to warrant a tree ensemble or gradient booster</li>
</ul></section><section id="links" class="level2"><h2 class="anchored" data-anchor-id="links">Links</h2>
<ul>
<li>GitHub: <a href="https://github.com/ielbadisy/mimar">github.com/ielbadisy/mimar</a>
</li>
</ul>
<hr>
<footer><a href="../../index.html#blog">Back to blog</a>
</footer>

</section><a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>R</category>
  <category>missing-data</category>
  <category>packages</category>
  <guid>https://elbadisyimad.com/blog/2025-08-15-mimar/</guid>
  <pubDate>Thu, 14 Aug 2025 23:00:00 GMT</pubDate>
  <media:content url="https://elbadisyimad.com/blog/2025-08-15-mimar/featured.png" medium="image" type="image/png" height="103" width="144"/>
</item>
<item>
  <title>funcml: A Formula-First Framework for Machine Learning in R</title>
  <dc:creator>Imad El Badisy</dc:creator>
  <link>https://elbadisyimad.com/blog/2025-06-01-funcml/</link>
  <description><![CDATA[ <p>Machine learning in R has long suffered from a fragmentation problem. Fitting a random forest, a regularized linear model, and a neural network each requires learning a different package, a different formula syntax, and a different set of conventions for prediction and evaluation. <strong>funcml</strong> was built to close that gap.</p>
<section id="what-is-funcml" class="level2"><h2 class="anchored" data-anchor-id="what-is-funcml">What is funcml?</h2>
<p><code>funcml</code> provides a unified, formula-first interface to supervised learning in R. Six top-level verbs cover the full ML workflow:</p>
<table class="caption-top table">
<thead><tr class="header">
<th>Verb</th>
<th>What it does</th>
</tr></thead>
<tbody>
<tr class="odd">
<td><code><a href="https://rdrr.io/pkg/funcml/man/fit.html">fit()</a></code></td>
<td>Train any learner via a common formula interface</td>
</tr>
<tr class="even">
<td><code><a href="https://rdrr.io/pkg/funcml/man/evaluate.html">evaluate()</a></code></td>
<td>Resampling-based performance with any metric</td>
</tr>
<tr class="odd">
<td><code><a href="https://rdrr.io/pkg/funcml/man/tune.html">tune()</a></code></td>
<td>Grid or random hyperparameter search</td>
</tr>
<tr class="even">
<td><code><a href="https://rdrr.io/pkg/funcml/man/compare.html">compare()</a></code></td>
<td>Benchmark multiple models side by side</td>
</tr>
<tr class="odd">
<td><code><a href="https://rdrr.io/pkg/funcml/man/interpret.html">interpret()</a></code></td>
<td>14 model-agnostic interpretability methods</td>
</tr>
<tr class="even">
<td><code><a href="https://rdrr.io/pkg/funcml/man/estimate.html">estimate()</a></code></td>
<td>Plug-in g-computation for ATE/CATE estimation</td>
</tr>
</tbody>
</table>
<p>Install from CRAN:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/utils/install.packages.html">install.packages</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"funcml"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
</section><section id="a-minimal-example" class="level2"><h2 class="anchored" data-anchor-id="a-minimal-example">A minimal example</h2>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;"><a href="https://rdrr.io/r/base/library.html">library</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;"><a href="https://CRAN.R-project.org/package=funcml">funcml</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># fit a random forest</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit_rf</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/funcml/man/fit.html">fit</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">Sepal.Length</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">.</span>, data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">iris</span>, model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ranger"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># evaluate with 5-fold CV</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/funcml/man/evaluate.html">evaluate</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">iris</span>, formula <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">Sepal.Length</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">.</span>, model <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ranger"</span>, resampling <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/funcml/man/cv.html">cv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>, seed <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>&lt;funcml_eval&gt; model: ranger | task: regression
  metric   mean     sd n std_error conf_level conf_low conf_high
1   rmse 0.3391 0.0451 5    0.0202       0.95   0.2830    0.3951
2    mae 0.2771 0.0303 5    0.0136       0.95   0.2394    0.3147
3    mse 0.1166 0.0322 5    0.0144       0.95   0.0767    0.1565
4  medae 0.2428 0.0391 5    0.0175       0.95   0.1943    0.2913
5   mape 0.0478 0.0050 5    0.0022       0.95   0.0416    0.0540
6    rsq 0.8236 0.0552 5    0.0247       0.95   0.7550    0.8922</code></pre>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># compare to a regularized regression</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/funcml/man/compare.html">compare</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span></span>
<span>  data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">iris</span>,</span>
<span>  formula <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">Sepal.Length</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">.</span>,</span>
<span>  models <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ranger"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"glmnet"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>,</span>
<span>  resampling <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/funcml/man/cv.html">cv</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>,</span>
<span>  seed <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>&lt;funcml_compare&gt; task: regression | tuned: FALSE
    model metric    mean     sd n std_error conf_level conf_low conf_high tuned
1  ranger   rmse  0.3391 0.0451 5    0.0202       0.95   0.2830    0.3951 FALSE
2  ranger    mae  0.2771 0.0303 5    0.0136       0.95   0.2394    0.3147 FALSE
3  ranger    mse  0.1166 0.0322 5    0.0144       0.95   0.0767    0.1565 FALSE
4  ranger  medae  0.2428 0.0391 5    0.0175       0.95   0.1943    0.2913 FALSE
5  ranger   mape  0.0478 0.0050 5    0.0022       0.95   0.0416    0.0540 FALSE
6  ranger    rsq  0.8236 0.0552 5    0.0247       0.95   0.7550    0.8922 FALSE
7  glmnet   rmse  0.8258 0.0670 5    0.0300       0.95   0.7426    0.9090 FALSE
8  glmnet    mae  0.6914 0.0683 5    0.0305       0.95   0.6066    0.7762 FALSE
9  glmnet    mse  0.6856 0.1110 5    0.0496       0.95   0.5478    0.8234 FALSE
10 glmnet  medae  0.6252 0.0687 5    0.0307       0.95   0.5399    0.7104 FALSE
11 glmnet   mape  0.1205 0.0104 5    0.0047       0.95   0.1076    0.1335 FALSE
12 glmnet    rsq -0.0175 0.0208 5    0.0093       0.95  -0.0433    0.0084 FALSE
   rank
1     1
2     1
3     1
4     1
5     1
6     1
7     2
8     2
9     2
10    2
11    2
12    2</code></pre>
</div>
</div>
</section><section id="interpretability-built-in" class="level2"><h2 class="anchored" data-anchor-id="interpretability-built-in">Interpretability built in</h2>
<p><code><a href="https://rdrr.io/pkg/funcml/man/interpret.html">interpret()</a></code> wraps 14 methods, from permutation importance and partial dependence plots to SHAP values and accumulated local effects, behind a single call:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/funcml/man/interpret.html">interpret</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fit_rf</span>, data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">iris</span>, method <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pdp"</span>, features <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Petal.Width"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">result</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">curves</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/utils/head.html">head</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>      feature     value     yhat
1 Petal.Width 0.1000000 5.555846
2 Petal.Width 0.2142857 5.567275
3 Petal.Width 0.3285714 5.573585
4 Petal.Width 0.4428571 5.654030
5 Petal.Width 0.5571429 5.644077
6 Petal.Width 0.6714286 5.656769</code></pre>
</div>
</div>
</section><section id="causal-estimation" class="level2"><h2 class="anchored" data-anchor-id="causal-estimation">Causal estimation</h2>
<p>When the research question goes beyond prediction, <code><a href="https://rdrr.io/pkg/funcml/man/estimate.html">estimate()</a></code> wraps plug-in g-computation to estimate average and conditional treatment effects:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/Random.html">set.seed</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">n</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">X1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/stats/Normal.html">rnorm</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">n</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>; <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">X2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/stats/Normal.html">rnorm</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">n</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">A</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/stats/Binomial.html">rbinom</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">n</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/stats/Logistic.html">plogis</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">X1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">Y</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">A</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">X1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">X2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/stats/Normal.html">rnorm</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">n</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mydata</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/data.frame.html">data.frame</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">Y</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">A</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">X1</span>, <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">X2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span></span>
<span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ATE of treatment A on outcome Y, adjusted for covariates X</span></span>
<span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/funcml/man/estimate.html">estimate</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span></span>
<span>  data      <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">mydata</span>,</span>
<span>  formula   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">Y</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">A</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">X1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">X2</span>,</span>
<span>  model     <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ranger"</span>,</span>
<span>  treatment <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"A"</span>,</span>
<span>  estimand  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ATE"</span>,</span>
<span>  seed      <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>&lt;funcml_estimand&gt; ATE via g-computation
Treatment: A (1 vs 0)
Estimate: 0.4531 | SE: 0.0156 | 95% normal CI [0.4225, 0.4836]</code></pre>
</div>
</div>
</section><section id="the-learner-registry" class="level2"><h2 class="anchored" data-anchor-id="the-learner-registry">The learner registry</h2>
<p><code>funcml</code> ships with 26 learners spanning linear models, tree ensembles, SVMs, neural networks, additive models, boosting, and stacking. All are accessed by name:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="downlit sourceCode r code-with-copy"><code class="sourceCode R"><span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/pkg/funcml/man/list_learners.html">list_learners</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"><a href="https://rdrr.io/r/base/c.html">c</a></span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"learner"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"has_tune"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>        learner has_tune
17     adaboost     TRUE
24         bart     TRUE
11          C50     TRUE
20      cforest     TRUE
19        ctree     TRUE
7      densemlp     TRUE
8     e1071_svm     TRUE
13        earth     TRUE
26      fastgbm     TRUE
16          fda     TRUE
14          gam     TRUE
10          gbm     TRUE
1           glm     TRUE
3        glmnet     TRUE
12         kknn     TRUE
21          lda     TRUE
23     lightgbm     TRUE
6           mlp     TRUE
15   naivebayes     TRUE
5          nnet     TRUE
18          pls     TRUE
22          qda     TRUE
9  randomForest     TRUE
4        ranger     TRUE
2         rpart     TRUE
27     stacking     TRUE
28 superlearner     TRUE
25      xgboost     TRUE</code></pre>
</div>
</div>
</section><section id="citation" class="level2"><h2 class="anchored" data-anchor-id="citation">Citation</h2>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode bibtex code-with-copy"><code class="sourceCode bibtex"><span id="cb12-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@software{El_Badisy_funcml_2026,</span></span>
<span id="cb12-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">  author  = {El Badisy, Imad},</span></span>
<span id="cb12-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">  license = {GPL-3.0-only},</span></span>
<span id="cb12-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">  month   = apr,</span></span>
<span id="cb12-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">  title   = {{funcml}},</span></span>
<span id="cb12-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">  doi     = {10.5281/zenodo.20707605},</span></span>
<span id="cb12-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">  url     = {https://doi.org/10.5281/zenodo.20707605},</span></span>
<span id="cb12-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">  version = {0.7.1},</span></span>
<span id="cb12-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">  year    = {2026}</span></span>
<span id="cb12-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
</section><section id="links" class="level2"><h2 class="anchored" data-anchor-id="links">Links</h2>
<ul>
<li>GitHub: <a href="https://github.com/ielbadisy/funcml">github.com/ielbadisy/funcml</a>
</li>
<li>CRAN: <a href="https://cran.r-project.org/package=funcml">CRAN.R-project.org/package=funcml</a>
</li>
<li>Citation: <a href="https://doi.org/10.5281/zenodo.20707605">doi:10.5281/zenodo.20707605</a>
</li>
</ul>
<hr>
<footer><a href="../../index.html#blog">Back to blog</a>
</footer>

</section><a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>R</category>
  <category>machine-learning</category>
  <category>packages</category>
  <guid>https://elbadisyimad.com/blog/2025-06-01-funcml/</guid>
  <pubDate>Sat, 31 May 2025 23:00:00 GMT</pubDate>
  <media:content url="https://elbadisyimad.com/blog/2025-06-01-funcml/featured.png" medium="image" type="image/png" height="94" width="144"/>
</item>
</channel>
</rss>
