Preprint
Article

This version is not peer-reviewed.

A Patient-Anchored, Physics-Informed Gradient-Boosting Virtual Sensor for Arterial Oxygen Saturation Across a Nine-Hour Blood-Gas Gap

Submitted:

02 October 2026

Posted:

05 October 2026

You are already at the latest version

Abstract
Arterial oxygen saturation measured by co-oximetry (SaO2m) is the clinical reference for oxygenation, but in the mechanically ventilated patients studied here the freshest usable value is nine hours old. We build a virtual sensor that bridges this gap from continuously recorded ventilator and gas-rig time series with gradient-boosted trees, and report it as three nested implementation scenarios of one code base: X0 (XGBoost 2.1.4 through our pipeline, no physics term active), XP (X0 plus a blend toward the anchor and the cumulative oxygen uptake rate over the gap per kilogram of body mass, derived from an oxygen balance of the arterial blood) and v4 (XP plus a patient-level anchor that recalibrates the nine-hour-old measurement toward the patient’s own history). Out-of-fold predictions under patient-grouped five-fold cross-validation are scored on the 3730 hours of 30 patients whose inputs contain no SaO2m value younger than nine hours. From X0 to XP, the mean per-patient MAPE decreases slightly, from 3.321% to 3.289%, an effect resolved by a paired patient bootstrap for this summary only. From XP to v4, it decreases further to 3.117%, the pooled MAPE decreases from 3.890% to 3.727% (both changes resolved by the bootstrap), and the pooled correlation increases from 0.754 to 0.793. Meanwhile, the model becomes substantially smaller, with the number of input features decreasing from 55 to 19 and the number of tree leaves decreasing from 9527 to 450. An exact decomposition of every prediction shows that in v4 the two-coefficient anchor earns 81% of the improvement over persistence and carries nearly all of the prediction variance. All formulas are matched line by line to the C++ and Python sources.
Keywords: 
;  ;  ;  ;  ;  ;  ;  ;  ;  
Subject: 
Engineering  -   Bioengineering

1. Introduction

Effective critical care depends on having timely and accurate knowledge of the patient’s physiological state, yet intensive care units operate under persistent structural constraints that systematically undermine this requirement [1]. High patient to nurse ratios, equipment saturation during surge periods, and the physical impossibility of continuous bedside observation for every admitted patient mean that clinically significant changes in physiology can go undetected for extended periods [2]. Laboratory based measurements remain the clinical standard for several critical physiological variables, including cardiac output [3] or arterial oxygen saturation SaO 2 via co-oximetry [4,5], yet when the samples of intensive-care patients are analysed in a central laboratory the median turnaround time between blood collection and result availability is 56 minutes, so that in practice some clinical decisions are grounded in delayed information [6].
This growing divergence between the current state and the most recent measurement is not an edge case but a structural property of any monitoring system that relies on intermittent invasive sampling [7,8]. Retrospective analyses of large ICU databases have documented that missing or delayed values in key physiological variables are systematically associated with suboptimal alarm management and delayed recognition of clinical deterioration [7,9]. For patients receiving mechanical ventilation, however, a continuously available high-resolution data source already exists: the ventilator itself, which continuously records a rich stream of respiratory signals that reflect the patient’s respiratory mechanics and gas-exchange capacity in real time [2,10]. The predictive value of this stream has already been established for within-ventilator prediction tasks, Qiu et al. [11] demonstrated that a long short-term memory relation network trained on MIMIC-III can predict patient-specific ventilator parameters in real time. If ventilator signals are sufficiently informative to predict future ventilator parameters, they should also carry information relevant to predicting other physiological variables, such as SaO 2 , as demonstrated by prior work linking ventilator settings to patient oxygenation outcomes [12,13]. This follows the soft-sensor paradigm, where continuously available signals are used to estimate intermittently measured variables [14].
Recent advances in soft sensing have shown that capturing long-range temporal structure is essential, [14] propose a temporal convolutional network with both spatial and temporal attention mechanisms, showing that temporally aware models are preferred for such task.
In the medical domain, the soft-sensor paradigm has been successfully applied across a broad range of continuous physiological estimation problems, establishing a strong precedent for the clinical feasibility of the approach [15]. Beyond oxygenation-related variables, soft-sensor approaches have been successfully explored for glucose monitoring, cardiovascular assessment, respiratory monitoring, intracranial pressure estimation, and wearable health applications, consistently demonstrating the potential of machine-learning models to infer clinically relevant physiological states from routinely collected signals [4,16,17,18,19,20,21,22,23].
Recent work in ICU time-series modeling emphasizes the importance of explicitly representing temporal dynamics under irregular sampling. Lee et al. [8,24] show that incorporating inter-event time gaps into recurrent architectures improves predictive performance by allowing models to exploit temporal spacing as an informative signal rather than treating it as missingness. Similarly, adaptive recurrent formulations that condition hidden state updates on elapsed time further improve modeling of heterogeneous physiological trajectories in critical care settings [25]. Patharkar et al. [7] summarize these findings across biomedical time-series applications, highlighting that methods accounting for irregular sampling consistently outperform standard sequence models.
Among physiological targets in critical care, oxygenation estimation has received growing attention, yet existing approaches leave the core problem of this study unresolved. Woo et al. [26] trained Random Forest and XGBoost models on a large-scale multi-centre ICU dataset to predict SaO 2 from SpO 2 and clinical covariates, reducing estimation error substantially over the pulse oximetry baseline, but the approach corrects an available SpO 2 signal rather than operating in its absence. Cabanas et al. [27] further highlight the regulatory and technical limitations of AI-enhanced pulse oximetry, reinforcing that SpO 2 -dependent correction methods have fundamental constraints in failure scenarios.
The closest line of work to ours estimates oxygenation directly from ventilator signals without relying on pulse oximetry. Where Ghazal et al. [28] trained a bootstrap-aggregated decision tree to predict SpO 2 categories five minutes after a ventilator setting change, achieving an AUC below 0.75 a result that also reveals the core limitation: a five-minute classification horizon is far too narrow to address the multi-hour sensor-absence scenario we target. Dong et al. [5] take a closer approach, using a non-linear additive model to estimate blood gas pH and PaCO 2 between invasive draws from ventilator-derived inputs, achieving clinically acceptable accuracy, but their target variable is not SaO 2 and the gap length is never varied or evaluated as a modeling parameter. Hser et al. [29] incorporate oxygenation estimation within a broader ICU respiratory monitoring system using gradient boosted models, predicting respiratory failure events up to ten hours ahead, but their estimator still takes SpO 2 as a continuous input, making it inapplicable when pulse oximetry is unavailable. Finally, Si et al. [30] estimate SpO 2 from facial video using Random Forest and Support Vector Regression, demonstrating non-contact sensing potential but under controlled low-acuity conditions incompatible with the mechanically ventilated ICU patient.
Across these works, three gaps remain open: no approach models prediction accuracy as a function of elapsed time since the last measurement, none operates without assuming SpO 2 availability, and none separates what a physical prior contributes from what the learned trees contribute under patient-level cross-validation. This paper addresses the three, building on the oxygen conservation law of our bioprocess soft sensors [31,32], on its transfer to human respiration [33,34], and on the maximum-relative-entropy weighting of our earlier estimators [32,35,36]. It bridges a nine-hour absence of the co-oximetry measurement from ventilator and gas-rig time series with gradient-boosted trees; it works without pulse oximetry; and it is reported as three explicit implementation scenarios of one code base, the unmodified library through our pipeline (X0), the library with our anchor blend and the cumulative oxygen uptake rate over the gap (XP), and the latter with a patient-level calibrated anchor (v4), so that every improvement is attributed to the code that produced it, every equation is matched to the line that implements it, and an exact decomposition of each prediction says how much of it is physics and how much is trees. The rest of the paper is organized as follows: Section 2 describes the data, the three scenarios, the shared boosted ensemble with a numeric trace of its leaves, the physics-informed terms with their derivations and code, and the evaluation protocol; Section 3 reports the three scenarios on identical folds, the anchor coefficients, the anatomy of the predictions and the ablations; Section 4 and Section 5 discuss and conclude.

2. Materials and Methods

The objective of this study is to predict S a O 2 m , the arterial oxygen saturation measured by co-oximetry, from hourly processed clinical variables, respiratory parameters and experimental gas-rig transducers, nine hours after the last available measurement. A principal characteristic of the study is the translation of soft-sensor technologies from bioprocess engineering to human physiological monitoring: as demonstrated by Kemesis et al. [34], industrial off-gas sensors can be adapted to the non-invasive continuous tracking of human respiratory gas exchange.
We define the dataset as the matrix X ∈ R n i × n m , where n i is the number of hourly samples and n m is the number of features that the boosted trees receive (its value depends on the scenario, Section 2.2), and the i-th row x i ∈ R n m is the feature vector of the i-th sample. The target vector is y ∈ R n i , the S a O 2 m values of every patient-hour. The mapping is
y ^ i = ϕ ( x i , θ )
where y ^ i is the predicted S a O 2 m of the i-th sample and ϕ ( · , θ ) is a regressor with learned parameters θ . Three implementations of ϕ are compared in this paper; they share one code base and differ in which of our additions are active.

2.1. Dataset and Preprocessing

The study cohort comprises n p = 31 mechanically ventilated patients, totaling 4 , 902 recorded hourly entries. Of these, n i = 4 , 017 hours have a measured target; all of them are predicted out of fold under five-fold patient-grouped cross-validation, and the results are reported on the 3 , 730 hours of 30 patients whose inputs contain no S a O 2 m value younger than nine hours (Section 3.7), with the values on all 4 , 017 hours listed alongside. In 322 patient-hours (644 rows, five patients) two blood gas measurements were documented within the same nominal hour. These rows are retained in the reported numbers; a sensitivity analysis keeping only the last measurement per hour is reported in Section 3.1.
The target variable is discrete and integer-valued, spanning 73 distinct levels from 20 % to 111 % (median 96 % , 1st percentile 52 % ; 350 observations fall below 85 % , and a single observation exceeding 100 % was retained as an authentic clinical recording). This discrete distribution is directly relevant to the mechanics of the persistence baseline (Section 3.6). All features entering the decision trees were standardized using Z-score normalization fitted strictly on the training folds; in contrast, all physiological quantities supplied directly to the analytical anchor (Section 2.4) were preserved in their raw, natural physical units.
Figure 1. Temporal problem formulation and prediction horizon. The model estimates the current oxygenation state y t by bridging a nine-hour absence of the co-oximetry measurement. The last available measurements y t − 9 and y t − 10 supply the physiological baseline; the continuous ventilator and gas-sensor channels supply the real-time information available at hour t.
Figure 1. Temporal problem formulation and prediction horizon. The model estimates the current oxygenation state y t by bridging a nine-hour absence of the co-oximetry measurement. The last available measurements y t − 9 and y t − 10 supply the physiological baseline; the continuous ventilator and gas-sensor channels supply the real-time information available at hour t.
Preprints 236351 g001
We define a prediction horizon of nine hours. The S a O 2 m history at t − 9 and t − 10 hours is included to establish the patient’s baseline prior to the simulated sensor gap, ensuring the model remains grounded in the patient’s physiological state without using future information. More precisely, the feature value provided at hour t represents the most recent observation recorded at or before t − 9 h . Consequently, the actual elapsed time since that baseline reading was taken is at least nine hours and varies depending on clinical sampling irregularity; its empirical distribution is analyzed in Section 3.6.

2.1.1. Signals and Their Lags in Each Scenario

Six real-time signals are engineered from the ventilator and the gas rig and lagged; three target-derived and two static descriptors complete the input. Table 1 lists the six signals with the lag hours that each scenario builds and, of those, the ones the trees are allowed to see. Table 2 lists the remaining columns. The counts differ between the scenarios: the trees of X0 and XP receive n m = 55 columns (six signals at hour t, their 44 lagged copies, and the five columns of Table 2 that are tree inputs), whereas the trees of v4 receive n m = 19 (five signals at t with two lags each, plus four of those five columns). In v4 the pruning of the lag lists was decided by tolerance tests on the out-of-fold macro MAPE (Section 3); the signal O2diffxPower (a signal which is proportional to Oxygen Uptake Rate, OUR) is hidden from the trees in v4 because it feeds the physics terms instead.
Table 1. Dynamic signals and their lag hours. Each cell lists the hours t and t − ℓ at which the signal enters the data as a column (data_preparation.py); the count in brackets is the number of such columns. In X0 and XP every column is a tree input. For O2diffxPower the listed hours are also the sampling hours L of the cumulative oxygen uptake rate, Eq. (16): the available values at these hours are averaged and the average is multiplied by the gap D and divided by the body mass; in v4 these columns serve only that purpose and are not tree inputs. O2conc: inspired O2 concentration at the mask inlet (%). GM102B_Volts: electrochemical gas-sensor output voltage (V). CO2xPower: expired CO2 concentration times the ventilator power integral. O2xPress: O2conc times airway pressure. O2xPressplusPEEP: O2conc times pressure plus PEEP, a delivery composite. O2diffxPower: inlet-minus-expiratory O2 concentration times the power integral, proportional to the oxygen uptake rate; it is the oxygen uptake rate signal OUR ( t ) of Section 2.4.
Table 1. Dynamic signals and their lag hours. Each cell lists the hours t and t − ℓ at which the signal enters the data as a column (data_preparation.py); the count in brackets is the number of such columns. In X0 and XP every column is a tree input. For O2diffxPower the listed hours are also the sampling hours L of the cumulative oxygen uptake rate, Eq. (16): the available values at these hours are averaged and the average is multiplied by the gap D and divided by the body mass; in v4 these columns serve only that purpose and are not tree inputs. O2conc: inspired O2 concentration at the mask inlet (%). GM102B_Volts: electrochemical gas-sensor output voltage (V). CO2xPower: expired CO2 concentration times the ventilator power integral. O2xPress: O2conc times airway pressure. O2xPressplusPEEP: O2conc times pressure plus PEEP, a delivery composite. O2diffxPower: inlet-minus-expiratory O2 concentration times the power integral, proportional to the oxygen uptake rate; it is the oxygen uptake rate signal OUR ( t ) of Section 2.4.
Signal Hours in X0 and XP (all tree inputs) Hours in v4 Of these, tree inputs in v4
O2conc t, t − 1 , 3 , 4 , 5 , 6 (6 cols) t, t − 1 , t − 6 t, t − 1 , t − 6 (3 cols)
GM102B_Volts t, t − 1 , 2 , 3 , 4 , 5 , 7 , 8 (8 cols) t, t − 1 , t − 8 t, t − 1 , t − 8 (3 cols)
CO2xPower t, t − 1 , 2 , 3 , 4 , 5 (6 cols) t, t − 1 , t − 5 t, t − 1 , t − 5 (3 cols)
O2xPress t, t − 1 , 2 , 3 , 4 , 5 , 6 , 8 , 11 , 12 (10 cols) t, t − 1 , t − 12 t, t − 1 , t − 12 (3 cols)
O2xPressplusPEEP t, t − 1 , 2 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 (11 cols) t, t − 1 , t − 11 t, t − 1 , t − 11 (3 cols)
O2diffxPower t, t − 1 , 2 , 4 , 5 , 7 , 8 , 10 , 11 (9 cols; also the sampling hours of Eq. (16) in XP) t, t − 1 , 2 , 4 , 7 (the sampling hours of Eq. (16)) none
tree inputs from this table: 50 15
Table 2. Target-derived and static columns. "Tree" says whether the boosted trees receive the column in that scenario; "anchor" says whether the column feeds the anchor of Section 2.4 instead. runmean_SaO2m exists only in v4.
Table 2. Target-derived and static columns. "Tree" says whether the boosted trees receive the column in that scenario; "anchor" says whether the column feeds the anchor of Section 2.4 instead. runmean_SaO2m exists only in v4.
Column Description X0, XP v4
SaO2m_lag_9h most recent S a O 2 m measured at or before t − 9 h (%); the persistence value y ( τ i ) of Eq. (17) tree and anchor tree and anchor
SaO2m_lag_10h most recent S a O 2 m measured at or before t − 10 h (%) tree tree
SaO2m_first the patient’s first S a O 2 m measurement (%) tree tree
runmean_SaO2m mean of all S a O 2 m measurements at or before t − 9 h, Eq. (20) not built anchor only
count_hours elapsed treatment time (h) tree tree
Svoris body mass (kg); also normalises the cumulative OUR term tree anchor scale only
tree inputs from this table 5 4
total tree inputs n m 55 19

2.2. Three Implementation Scenarios

Every number in this paper is attributed to one of three scenarios of one code base (Python pipeline and a patched XGBoost 2.1.4 C++ library). They are nested: each adds to the previous one and changes nothing else.
  • X0—XGBoost. The XGBoost 2.1.4 library, trained by our Python pipeline with the tree inputs of Table 1Table 2 ( n m = 55 ), the initial prediction equal to the persistence value y ( τ i ) , the cost-sensitive weights of Section 2.3, and the hyper-parameters of Table 8. The two C++ terms added for XP are compiled into the library used here as well, but both coefficients are zero ( β = β 1 = 0 in Eq. (37)), which makes them identities: X0 produces what unmodified XGBoost 2.1.4 produces from the same pipeline, up to float32 rounding.
  • XP — XGBoost with our anchor blend and cumulative OUR term. X0 plus the two C++ terms of Section 2.6 with their configured coefficients β = 0.1418 and β 1 = 0.00139 : the final prediction is pulled toward the persistence value and receives the cumulative oxygen uptake rate over the gap per kilogram of body mass, Eq. (16). Same trees, same n m = 55 .
  • v4 — XP with the patient-level calibrated anchor. XP plus the anchor of Section 2.4.5, which replaces the raw persistence value by a least-squares combination of the persistence value and the patient’s own measurement history, fitted on each training fold; its trees receive n m = 19 inputs and the hyperparameters of Table 9. β = 0.3677 , β 1 = 0.00124 .
Every code excerpt and equation in this paper follows a unified typographical convention.
In code listings: dark gray denotes unmodified upstream XGBoost (v2.1.4) source code; regular black font indicates our additions active in both XP and v4 (our Python pipeline and C++ extensions); and bold font denotes additions active exclusively in v4. Excerpts of original XGBoost source in Section 2.5 are therefore rendered entirely in gray.
In equations: our contributions carry the label [XP] if active in both XP and v4, and are set in bold with the label [v4] if unique to v4. Standard equations from baseline XGBoost or established physiological literature remain unmarked. Table 3 lists every mathematical symbol with its unit and corresponding code variable.

2.3. The Loss: Cost-Sensitive Sample Weights and the Relative-Entropy Criterion

Two fits in this paper minimise a weighted sum of squared errors over the training rows: the least-squares fit of the patient-level anchor of v4 (Section 2.4.5) and the boosted trees of all three scenarios (Section 2.5). Both use one dimensionless weight per row,
w i = 1 − k w | y i | ν + ε + k w ,
where y i is the target in %, k w ∈ [ 0 , 1 ] is a dimensionless floor (custom_kp), ν ≥ 0 a dimensionless exponent (custom_power) and ε = 10 − 6 a stabiliser in % ν (custom_eps); the three are fields of config.py, class TrainConfig, and the weights are the array sw computed by compute_sample_weights (utils_prediction.py). The weights are the same in the three scenarios up to the values of k w and ν (Table 8 and Table 9).
The family (2) descends from our maximum-relative-entropy estimators [31,32,35], where it was written for the biomass concentration of a cultivation with a fixed square in place of the exponent ν , and its single coefficient was named K e x p ; in the notation of this paper that coefficient is k w and the observed quantity is y i . For a Gaussian density P p o s t of the prediction y ^ i and a Gaussian likelihood P l i k centred on the observation y i with variance σ i 2 (in % 2 ), the relative entropy of row i is [32]
S i = − ∫ P p o s t ( y ^ ) ln P p o s t ( y ^ ) P l i k ( y ^ ) d y ^ = − y ^ i − y i 2 2 σ i 2 + const ,
dimensionless, with the variance model [32]
σ i 2 = σ 0 2 | y i | ν 1 − k w + k w | y i | ν ,
in which σ 0 2 is a constant scale in % 2 , y i enters with its numerical value in %, and ν = 2 gives the printed form of the cited papers. Inserting Eq. (4) into Eq. (3) and summing over the training rows gives
Table 3. Symbols, units and names in the code (dp: data_preparation.py; up: utils_prediction.py; lc: src/learner.cc). a.u.: arbitrary units of the gas signals.
Table 3. Symbols, units and names in the code (dp: data_preparation.py; up: utils_prediction.py; lc: src/learner.cc). a.u.: arbitrary units of the gas signals.
Symbol Meaning Unit Name in the code
i, n i row (one patient-hour), number of rows — row of the data frame
p ( i ) , n p patient of row i, number of patients — patient_id
t i hour of row i h LocalTime
y i measured S a O 2 m , the target % SaO2m
D nominal gap h virtual_sensor_gap = 9
τ i , D i time and age of the last measurement available at t i , Eq. (17) h inside _time_based_lag_last_known (dp)
y ( τ i ) last available measurement % SaO2m_lag_9h; raw_lag_tr, raw_lag_va (up)
H i ; y ¯ H i measurement times available at t i − D ; mean of y over them, Eq. (20) h; % runmean_SaO2m
m i k g body mass kg Svoris
OUR ( t ) oxygen uptake rate signal at the airway a.u. O2diffxPower
CPR ( t ) carbon dioxide production rate signal a.u. CO2xPower
k O U R , k C P R coefficients of the balance, Eq. (13) % kg h−1 a.u.−1 —
L lag set of the OUR signal h lags of O2diffxPower
cOUR i cumulative oxygen uptake rate over the gap per kg, Eq. (16) a.u. h kg−1 integral_O2diffxPower; field custom_integral
y ^ 0 , i initial prediction, the anchor % raw_base_train, raw_base_val; base_margin; anchor (lc)
c 0 ; c 1 , c 2 coefficients of the patient-level anchor, Eq. (20) %; — coef[0]; coef[1], coef[2] (up)
w i sample weight, Eq. (2) — sw
k w ; ν ; ε floor, exponent and stabiliser of w i , Eq. (2) —; —; % ν custom_kp, custom_power, custom_eps
b, n b boosting round, number of trees — rounds of xgb.train
f b , s b , j tree b, score of its leaf j % XGBoost internal
η learning rate — learning_rate
λ ; α ; γ L2, L1 and per-split penalties —; %; % 2 reg_lambda, reg_alpha, gamma
g b , i , h b , i gradient and Hessian of row i in round b %, — XGBoost internal
y ^ b , i ; y ^ n b , i running and raw boosted prediction % prediction buffer; preds (lc)
y ˜ i final prediction, Eq. (37) % pred_val, pred_tr (up)
β ; β 1 anchor blend; weight of cOUR i —; % kg h−1 a.u.−1 custom_b, custom_b1
K L a ; p O 2 * , PaO 2 * precursor model: mass transfer capacity; maximal oxygen solubility s−1; mmHg —
− 2 ∑ i S i = 1 σ 0 2 ∑ i 1 − k w | y i | ν + k w y i − y ^ i 2 + const ,
whose bracket is Eq. (2) with ε = 0 . The weighted squared loss used below is therefore the relative-entropy criterion of [32], generalised by the exponent ν and the stabiliser ε  [36]; k w is the single coefficient that trades the error relative to | y i | ν (the MAPE end, k w → 0 ) against the squared error (the variance end, k w → 1 ). Its measured effect on this cohort is given in Section 3.5.

2.4. From the Oxygen Balance to the Physics-Informed Terms

This subsection derives, from the oxygen conservation law of our earlier work, the two terms that the scenarios add to the boosted trees of Section 2.5: the cumulative oxygen uptake rate of XP, Eq. (16), and the patient-level anchor of v4, Eq. (20). The derived columns integral_O2diffxPower and runmean_SaO2m are removed from the tree inputs (utils_prediction.py, _extract_base_margin) and reach the model only through these terms.

2.4.1. Precursors: the Oxygen Conservation Law of Our Earlier Work

In aerobic bioprocesses, at a stationary oxidative state the oxygen uptake rate of the culture, OUR, equals the oxygen transfer rate from the gas, OTR, both in amount of oxygen per unit volume and time [31,33]:
OUR = OTR .
In the time domain the same conservation law reads [33,37]: the dissolved oxygen, written as its partial pressure p O 2 (mmHg), accumulates by what is transferred minus what is taken up,
d p O 2 ( t ) d t + OUR ( t ) = OTR p O 2 ( t ) , t ,
and the transfer is proportional to the distance from the maximal oxygen solubility p O 2 * (mmHg), with the oxygen mass transfer capacity K L a (s−1) [33]:
OTR p O 2 ( t ) , t = K L a p O 2 * ( t ) − p O 2 ( t ) .
Substituting Eq. (8) into Eq. (7) and replacing the dissolved oxygen of the nutritional medium by the partial pressure of oxygen in arterial blood, PaO 2 (mmHg), Survyla et al. [33] and Kemesis et al. [34] obtained the model of arterial oxygen they applied to a human volunteer and to ventilated children,
d PaO 2 ( t ) d t = K L a PaO 2 * ( t ) − PaO 2 ( t ) − k O U R OUR ( t ) ,
in which OUR ( t ) is the airway signal of their gas-analysis device and k O U R its calibration coefficient, so that k O U R OUR ( t ) is in mmHg s−1 (in [33], Table I: k O U R = 1.408 , K L a = 0.4217  s−1, PaO 2 * = 120.2  mmHg for one volunteer). To use sampled data, Survyla et al. [33] integrated the balance between two neighbouring sample times t i − 1 and t i (s) and divided both sides by the interval Δ t i , i − 1 = t i − t i − 1 , a bar denoting the average over the interval (their Eqs. (8)–(9)); applied to Eq. (9) this step gives
PaO 2 ( t i ) − PaO 2 ( t i − 1 ) Δ t i , i − 1 + k O U R OUR ¯ = K L a PaO 2 * ¯ − PaO 2 ¯ .
Integrating the rate before using it is also the idea of the cumulative oxygen uptake rate cOUR [31]: the integral of OUR is less noisy than OUR itself. Two features of Eq. (9) do not fit the present task. It is written for partial pressure, and in the trial of [33] the haemoglobin saturation did not change noticeably, so the dissociation curve played no role, whereas here the target is the saturation itself. And it needs K L a and PaO 2 * , which were identified per person from blood gases, whereas no per-patient calibration is available at prediction time here.

2.4.2. The Balance Used Here: Saturation, Whole-Body Amounts, Body Mass on the Left

Three physiological facts connect Eq. (7) to the saturation y (%). The oxygen content of arterial blood, C a O 2 (mL O2 per dL of blood), is carried almost entirely by haemoglobin, of concentration Hb (g/dL) [38]:
C a O 2 = 1.34 Hb y 100 + 0.003 PaO 2 ;
at Hb = 14 g/dL, y = 95 % and PaO 2 = 100 mmHg the dissolved term is 0.3 against 17.8 mL/dL bound to haemoglobin. The amount of oxygen in the circulating blood is the content times the blood volume V b (dL), and the blood volume is proportional to the body mass m k g (kg), V b = k b m k g with k b ≈ 0.7 dL/kg in adults [39]. Written for amounts instead of concentrations, Eq. (7) states that the oxygen held in the blood changes by the oxygen taken from the ventilator gas, V ˙ O 2 a i r (mL O2 h−1), which is what the airway signal measures (inspired minus expired oxygen times the gas flow [40]), minus the oxygen consumed by the tissues, which equals the carbon dioxide production V ˙ CO 2 (mL CO2 h−1) divided by the dimensionless respiratory quotient RQ. With body mass on the left:
k b m k g d C a O 2 ( t ) d t = V ˙ O 2 a i r ( t ) − V ˙ CO 2 ( t ) RQ .
Eq. (12) is the conservation law of Eq. (7), as is Eq. (9) and its sampled form Eq. (10); Table 4 lists how each term of Eq. (10) corresponds to a term of Eq. (12) and of its integrated form, Eq. (15) below. The difference is the closure. Eq. (10) models the transfer from the gradient, K L a ( PaO 2 * − PaO 2 ) , and uses the airway signal as the uptake, the two being equal in the stationary state of Eq. (6). Eq. (12) takes the transfer into the blood from the airway signal, which is what that signal physically measures, and takes the tissue consumption from the CO2 production; it therefore needs neither K L a nor PaO 2 * .
Table 4. Correspondence between the precursor balance, Eq. (10), and the balance of this paper, Eqs. (12) and (15).
Table 4. Correspondence between the precursor balance, Eq. (10), and the balance of this paper, Eqs. (12) and (15).
Role in the balance Precursor, Eq. (10) This paper, Eqs. (12), (15)
state variable PaO 2 (mmHg), per unit volume y (%) through C a O 2 , Eq. (11), whole body through k b m k g
accumulation change of PaO 2 over Δ t i , i − 1 change of y over the gap D
transfer into the blood K L a ( PaO 2 * ¯ − PaO 2 ¯ ) , modelled V ˙ O 2 a i r , measured at the airway as OUR ( t )
consumption k O U R OUR ¯ , from the airway signal V ˙ CO 2 / RQ , from CPR ( t ) ; not used in the three scenarios ( k C P R = 0 )
time step interval between two samples gap D = 9 h
The assumptions are: (A1) the arterial blood is one well-mixed compartment whose volume k b m k g does not change over the gap; (A2) Hb is constant over the gap and the dissolved term of Eq. (11) is neglected, so d C a O 2 / d t = ( 1.34 Hb / 100 ) d y / d t ; (A3) the airway signal OUR ( t ) , the column O2diffxPower (inlet-minus-expiratory O2 concentration times the ventilator power integral, in arbitrary units a.u.), is proportional to the oxygen taken from the gas, V ˙ O 2 a i r = c O U R OUR ( t ) with c O U R in mL O2 h−1 a.u.−1, the power integral standing for the gas flow; (A4) the signal CPR ( t ) , the column CO2xPower (a.u.), is proportional to the CO2 production, V ˙ CO 2 = c C P R CPR ( t ) with c C P R in mL CO2 h−1 a.u.−1, and RQ is constant over the gap; (A5) these constants are shared by the patients of a training fold; (A6) the hourly samples are missing at random. Substituting (A2)–(A4) into Eq. (12) and collecting the constants into k O U R = 100 c O U R / ( 1.34 Hb k b ) and k C P R = 100 c C P R / ( 1.34 Hb k b RQ ) , both in % kg h−1 a.u.−1, gives the balance with body mass on the left,
m k g d y ( t ) d t = k O U R OUR ( t ) − k C P R CPR ( t ) ,
and dividing both sides by m k g ,
d y ( t ) d t = k O U R OUR ( t ) m k g − k C P R CPR ( t ) m k g .
This is why the oxygen uptake signal enters the code per kilogram of body mass. In the three scenarios of this paper the consumption term of Eq. (14) is not used: its coefficient k C P R is zero there, and only the uptake term is carried from here on.

2.4.3. Integration over the Gap: the Cumulative Oxygen Uptake Rate

Integrating Eq. (14) over the gap ( t i − D , t i ] , as Eq. (10) integrates between samples, with t i the hour of row i and D = 9 h (config.py, virtual_sensor_gap):
y ( t i ) − y ( t i − D ) = k O U R ∫ t i − D t i OUR ( s ) m i k g d s ,
where m i k g is the last known body mass of the patient of row i (column Svoris; for a patient with no recorded mass the mean over the patients). The integral is the cumulative oxygen uptake rate of [31], taken over the gap and per kilogram. The code evaluates it with the rectangle rule from the OUR values recorded at the hours of the lag set L (h), the lags of Table 1 plus the current hour ( L = { 0 , 1 , 2 , 4 , 5 , 7 , 8 , 10 , 11 } in X0 and XP, { 0 , 1 , 2 , 4 , 7 } in v4): the available values are summed, the sum is divided by their number | L i | ( L i ⊆ L , the hours at which a value exists for row i), and the average is multiplied by the width D of the integration interval and divided by the body mass:
cOUR i = D m i k g · 1 | L i | ∑ ℓ ∈ L i OUR ( t i − ℓ ) ≈ ∫ t i − D t i OUR ( s ) m i k g d s [ XP ] ,
in a.u. h kg−1 (column integral_O2diffxPower, Listings 1 and 2; the mean over the available columns is mean(axis=1, skipna=True)). Under (A6) the sample mean is unbiased for the time average of OUR / m k g over the gap, so Eq. (16) is unbiased for the integral [41]; the plain sum ∑ ℓ OUR ( t i − ℓ ) · 1 h would equal | L i | / D times it and shrink with every missing hour. If OUR / m k g is Lipschitz with constant Λ (a.u. kg−1 h−1), the error of the rectangle rule on an hourly grid is at most 1 2 Λ D · 1 h  [42]. The factor is the gap D and not the number of columns; the two coincide in X0 and XP when all nine values are present ( | L i | = D = 9 ) but not in v4, and the factor D keeps the units when lags are pruned. Only the row’s own signals up to t i are used.
Preprints 236351 i001
Preprints 236351 i002

2.4.4. The Last Available Measurement

The measurement of y that the sensor may use at hour t i is the most recent one taken at or before t i − D :
τ i = max { s ≤ t i − D : y ( s ) observed for patient p ( i ) } , D i = t i − τ i ≥ D ,
where D i denotes the actual elapsed time (in hours). The term y ( τ i ) corresponds to the nine-hour lagged oxygen saturation (SaO2m_lag_9h), representing the most recent measurement recorded at or before t i − D . During the initial hours of an ICU admission before a nine-hour history is established ( t i < D ), this value defaults to the patient’s first recorded measurement. Substituting y ( τ i ) for y ( t i − D ) and substituting Eq. (16) into Eq. (15) yields the integrated oxygen mass balance,
y i ≈ y ( τ i ) + k O U R cOUR i ,
whose two terms the scenarios use as listed in Table 5. In X0 and XP the initial prediction of the boosted trees is the last available measurement itself,
y ^ 0 , i = y ( τ i ) ( X 0 , XP ) ,
so the trees learn corrections to the nine-hour-old measurement rather than to a constant.
Table 5. How each scenario uses the terms of the integrated oxygen balance, Eq. (18).
Table 5. How each scenario uses the terms of the integrated oxygen balance, Eq. (18).
Term X0 XP v4
y ( τ i ) initial prediction, Eq. (19) initial prediction, Eq. (19) recalibrated toward the patient’s history, Eq. (20)
k O U R cOUR i not used β 1 cOUR i in Eq. (37), β 1 = 0.00139 β 1 cOUR i in Eq. (37), β 1 = 0.00124
β 1 is found by tuning, not by least squares, and in X0 and XP the trees also receive the OUR signal columns, so β 1 is not an estimate of k O U R ; both multiply the cumulative oxygen uptake per kilogram over the gap.

2.4.5. Scenario v4: the Patient-Level Anchor

Let H i = { s ≤ t i − D : y ( s ) observed for p ( i ) } be the times of all measurements of the patient available at t i − D ; the same information as y ( τ i ) uses, so no new leakage enters. In v4 the initial prediction recalibrates the last available measurement toward the patient’s own past mean:
y ^ 0 , i = c 0 + c 1 y ( τ i ) + c 2 y ¯ H i , y ¯ H i = 1 | H i | ∑ s ∈ H i y ( s ) [ v 4 ]
with c 0 in % and c 1 , c 2 dimensionless, and y ¯ H i : = y ( τ i ) when H i is empty (the first D hours of a stay; utils_prediction.py). y ¯ H i is the column runmean_SaO2m (data_preparation.py, compute_target_runmean). The three coefficients are the weighted least-squares solution on the training rows T of the fold, with the weights w i of Eq. (2):
( c 0 , c 1 , c 2 ) = arg min ∑ i ∈ T w i y i − y ^ 0 , i 2 [ v 4 ]
with y ^ 0 , i defined by Eq. (20). In the implementation, the three anchor coefficients ( c 0 , c 1 , c 2 , representing the intercept, persistence weight, and historical patient mean) are solved in Python and transferred via the base_margin field of the training and validation DMatrix objects. In the C++ core, this directly populates base_margin_ ( y ^ 0 , i ), which acts as the initial reference score for each row in the tree recursion (Section 2.5) and the physiological anchor of the final ensemble prediction in Eq. (37).
Each cross-validation fold estimates these coefficients strictly using its training cohort and applies them out-of-fold to the held-out validation patients. The resulting fold-averaged coefficients are c 0 = 3.368 , c 1 = 0.2472 , and c 2 = 0.7170 (Section 3). Because c 1 + c 2 = 0.964 , Eq. (20) represents, to within four percent, a weighted combination between the last measured blood gas ( 26 % ) and the patient’s long-term historical baseline ( 74 % ). The theoretical rationale for assigning a weight strictly below unity to y ( τ i ) is regression attenuation [43,44]: framing the observed measurement as y ( τ i ) = μ i + ξ i , where μ i is the true underlying physiological state and ξ i represents independent measurement noise, the least-squares shrinkage slope on y ( τ i ) is
c 1 * = Var ( μ ) Var ( μ ) + Var ( ξ ) < 1 ,
and y ¯ H i carries the same level with less noise, so Eq. (21) moves weight from y ( τ i ) to y ¯ H i , a shrinkage toward the patient’s own level [45].
Preprints 236351 i003
Preprints 236351 i004

2.5. The Boosted Tree Ensemble Shared by the Three Scenarios

The three scenarios share one boosted ensemble; what differs between them enters only through the initial prediction y ^ 0 , i and the final prediction of Section 2.6. This subsection therefore describes the ensemble once. What is ours in this subsection. The ensemble is XGBoost 2.1.4 unchanged in all three scenarios; Section 2.5.1 states the four relations of its algorithm that our code touches and the three places where it does, without reproducing its derivations. Our contribution enters the ensemble at one place: the initial prediction y ^ 0 , i from which the recursion of Eq. (31) starts, which is y ( τ i ) in X0 and XP, Eq. (19), and the patient-level anchor of Eq. (20) inv4. The final prediction of XP and v4, Eq. (37), is formed after the last tree and is not part of the recursion. Units: y i , y ^ b , i , f b , the leaf scores s b , j and the gradients g b , i are in %; w i , the Hessians h b , i and their sums, λ and η are dimensionless; α is in %, the unit of the gradient sums; γ and the split gain are in % 2 ; the inputs x i , m are Z-scores. The library we patched and ran is XGBoost release 2.1.4; the excerpts of original XGBoost code in this subsection are copied, with their line numbers, from the release 2.1.4 files of the library we patched and ran, and are typeset in grey; the lines of our own additions are cited against the same sources (Section 2.4 and Section 2.6).
Boosting algorithms, such as the foundational AdaBoost [46], build ensemble models sequentially, where each new tree is specifically trained to correct the errors made by its predecessors [47]. XGBoost [47] improves upon traditional boosting by introducing a sparsity-aware split-finding algorithm for sparse data and a regularized learning objective to prevent overfitting, an approach since validated across many tabular clinical-prediction tasks [26,29]. Throughout this subsection the symbol ≡ denotes a definition. To keep the presentation uniform, every displayed equation is stated first and its newly introduced symbols are defined immediately afterwards in a where clause. The only exceptions are the few symbols that need a sentence of conceptual set-up (such as the routing q b and the leaf-score vector s b below): these are introduced in the prose that motivates their equation and are then not repeated. In no case is a symbol defined twice. The fixed global counts are written as n with a subscript naming what is counted: i ∈ { 1 , … , n i } indexes the n i training samples, m ∈ { 1 , … , n m } indexes the n m features, and b ∈ { 1 , … , n b } indexes the n b boosting rounds (equivalently, the n b trees). The one count that varies from tree to tree, the number of leaves, is written T b , with leaf index j ∈ { 1 , … , T b } ; it is a deliberately separate symbol from the tree count n b so the two can never be confused.

Input, target, and prediction.

Following the notation of Section 1, each sample i is one mechanically ventilated patient at one hour, described by the feature vector x i ∈ R n m of Table 1 and Table 2, where n m is the number of features. The value of n m is a property of the scenario (Section 2.2, Table 1Table 2): in X0 and XP the trees receive n m = 55 columns, the six real-time signals at hour t, their 44 lagged copies, and five target-derived or static descriptors; in v4 they receive n m = 19 , five signals at t with two lags each and four descriptors. Grouping the columns by block, the input vector is
x i = ( x i , 1 , … , x i , n s ︸ n s signals at hour t , x i , n s + 1 , … , x i , n s + n ℓ ︸ the same signals at their lag hours , x i , n s + n ℓ + 1 , … , x i , n m ︸ target history and static descriptors ) ⊤ ∈ R n m ,
with ( n s , n ℓ , n m ) = ( 6 , 44 , 55 ) in X0 and XP and ( 5 , 10 , 19 ) in v4, where each component x i , m ∈ R (for i = 1 , … , n i and m = 1 , … , n m ) is a single scalar feature and the superscript ⊤ denotes transposition, so x i is a column vector. The ground truth y i ∈ [ 0 , 100 ] is the co-oximetry oxygen saturation in percent at hour t, a single scalar; to make every symbol concrete enough to check by hand, a small running example throughout this subsection uses five hypothetical hourly samples with target vector y = ( 88 , 90 , 91 , 93 , 95 ) ⊤ . These five are a didactic device for hand-calculation and do not redefine the dataset size, which in our actual run is n i = 4017 in every scenario. Finally, the model’s prediction for sample i is a single scalar y ^ i ∈ R : its estimate of the true target y i , obtained by mapping the feature vector x i through the ensemble. Input x i , target y i , and prediction y ^ i are the three quantities this paragraph names; the next paragraph constructs the map x i ↦ y ^ i explicitly.

From the input to a prediction.

Having fixed what a single input x i from Eq. (23) is, we now build the function that turns it into the estimate y ^ i . Chen and Guestrin [47] construct this function as a sum of n b regression trees, each tree adding one correction to the running estimate:
y ^ n b , i = ϕ ( x i ) = y ^ 0 , i + η ∑ b = 1 n b f b ( x i ) , f b ∈ F ,
where y ^ n b , i is the raw boosted estimate of S a O 2 m for sample i after the last round, ϕ denotes the full ensemble, y ^ 0 , i is the per-row initial prediction of Section 2.4 (Eq. (19) in X0 and XP, Eq. (20) inv4), η is the learning rate defined at Eq. (31), n b is the number of boosting rounds (capped at 2000 and chosen per fold by early stopping: on average 792.4 trees in X0 and XP, 83.2 in v4), and f b is the b-th regression tree, drawn from the tree space F defined next. In X0 the final prediction is y ˜ i = y ^ n b , i ; in XP and v4 it is the blend of Eq. (37).

What a single tree is.

A regression tree is a finite set of yes/no questions arranged as a binary tree, each question of the form "is feature m of the sample below the threshold ϑ ?", together with one number stored at every leaf. To evaluate the tree on a sample, one starts at the root, answers the question, moves to the left child on "yes" and to the right child on "no", and repeats until a leaf is reached; the tree’s output is the number stored at that leaf. Two objects therefore describe tree b completely. The first is the routing q b , which is the branch structure written as a function: q b ( x i ) ∈ { 1 , … , T b } is the index of the leaf that sample i reaches, and q b : R n m → { 1 , … , T b } is defined for any feature vector, including ventilator readings never seen during training. The second is the leaf-score vector s b = ( s b , 1 , … , s b , T b ) ⊤ ∈ R T b , one number per leaf. With j = q b ( x i ) the leaf reached, the output of the tree is
f b ( x i ) = s b , j , j = q b ( x i ) .
The same routing fixes which training samples share a leaf, and the objective derived below sums over those per-leaf groups; q b reappears in that role in Eq. (33).
F = f b : x ↦ s b , q b ( x ) | q b : R n m → { 1 , … , T b } , s b ∈ R T b .
The same routing fixes which training samples share a leaf, and the objective derived below sums over those per-leaf groups; q b reappears in that role in Eq. (33).

A concrete tree.

The purpose of this example is deliberately narrow: to exhibit the abstract pair ( q b , s b ) of the previous paragraph on a tree small enough to check by hand. It draws on two results that are only derived later, how a leaf score is obtained in closed form (Eq. (35), Section 2.5.1) and how a split is chosen (Section 2.5.1), and states them here without proof so that the objects can be seen in action before the machinery that produces them is built. This illustrate first, derive later ordering is common in expository treatments; a reader may take the two results on trust until those sections. Concretely, take f b to be a depth-1 tree whose root splits on the inspired oxygen concentration O 2 conc at hour t, the first feature of the input, i.e. component x i , 1 of x i in Eq. (23), producing T b = 2 leaves:
q b ( x i ) = 1 , x i , 1 ≤ 40 % , 2 , x i , 1 > 40 % , s b = ( s b , 1 , s b , 2 ) ⊤ .
The indices here are worth spelling out, because three different roles meet in this one equation. The value being tested, x i , 1 , is a feature of samplei, so it carries the sample index i and the feature index 1; it does not carry the round index b, since the input does not depend on which tree reads it. What does belong to tree b is the split rule, the choice to branch on component 1 and the threshold 40 % are parameters of this particular f b , which is exactly why the routing q b carries the subscript b. And the leaf index j does not appear on the input side at all: it is the output of the routing, j = q b ( x i ) ∈ { 1 , 2 } , fed into Eq. (25) to read the score. Concretely, sample i with x i , 1 = 35 % gives q b ( x i ) = 1 , so by (25) the tree outputs f b ( x i ) = s b , 1 ; sample i with x i , 1 = 55 % gives q b ( x i ) = 2 and output s b , 2 . Neither part of this tree is chosen by hand. XGBoost learns the leaf scores s b , 1 , s b , 2 from the data through the closed form () below, and it learns the split structure, which feature each node tests, and at what threshold, through the greedy search of Section 2.5.1, which scans the candidate thresholds of every feature and keeps the one that maximizes the split gain (). The number 40 % is a didactic placeholder chosen to keep the arithmetic legible; it is not a fitted value from our run. The quantity it stands for is, at training time, the C++ variable split_pt that EnumerateSplit selects for the node (the third argument of best.Update in the listing of Section 2.5.1); once training finishes, that value is stored as the node’s split condition inside the fitted booster and can be read back from the Python model with model.get_booster().trees_to_dataframe() (the Split column) or get_dump(). All split thresholds and leaf weights are determined automatically by the tree-growing algorithm via gradient-based gain maximization during training, rather than by manually specified decision rules.
In the source code, a tree’s prediction and the objective registered as reg:squarederror are realized by the LinearSquareLoss struct; the routing and leaf storage are handled by the tree builder discussed in Section 2.5.1.1

How the trees are chosen: the training objective.

The ensemble (24) is only as good as the trees placed in it, so the trees are selected to minimize a training objective that balances how well the model fits the data against how complex it becomes. The objective is assembled from two ingredients. The first is the data-fit term: inserting the ensemble prediction y ^ i = ϕ ( x i ) of Eq. (24) into the squared-error loss ℓ ( y i , y ^ i ) = 1 2 ( y i − y ^ i ) 2 (the factor 1 2 is a convention that makes the gradient in Eq. (32) clean and does not change the minimizer) and summing over all n i samples gives the total prediction error ∑ i = 1 n i ℓ ( y i , y ^ i ) . The second is a complexity penalty charged to each individual tree f b ,
Ω ( f b ) = γ T b + 1 2 λ ∑ j = 1 T b s b , j 2 ,
which grows with that tree’s number of leaves T b (penalty rate γ ≥ 0 , the gamma parameter, left at its default 0 in our runs) and with the squared magnitude of its leaf scores s b , j ∈ R (rate λ ≥ 0 , the L 2 strength reg_lambda  = 5 ); the index j ∈ { 1 , … , T b } runs over the leaves of that one tree, and s b , j is the score at leaf j of tree b (the j-th component of s b ). Now, because the ensemble of Eq. (24) is the sum of all n b trees, y ^ i = ∑ b = 1 n b f b ( x i ) , the model’s total complexity is the sum of these per-tree penalties — one Ω ( f b ) term for each of the n b trees — and this is precisely where the second summation below comes from. Adding the two ingredients yields the regularized objective of Chen and Guestrin [47]:
L ( f 1 , … , f n b ) = ∑ i = 1 n i ℓ y i , y ^ i ︸ total prediction error ( sum over n i samples ) + ∑ b = 1 n b Ω ( f b ) ︸ summed complexity ( sum over n b trees ) .
The two summations run over different index sets and therefore cannot be merged: the first is indexed by the sample i = 1 , … , n i , the second by the tree b = 1 , … , n b . Nor can the complexity be pulled outside its own sum, because Ω ( f b ) genuinely differs from tree to tree — the leaf count T b and the scores s b , j both depend on b, while only the rates γ , λ are shared — which is exactly why each carries the tree subscript b.

Making the loss cost-sensitive.

Finally, to make the predictions more sensitive to clinically critical low saturations, we insert the cost-sensitive sample weight w i of Eq. (2) into each loss term of the objective (29). This single substitution yields the weighted objective actually optimized in this study:
L ( f 1 , … , f n b ) = ∑ i = 1 n i w i · ℓ y i , y ^ i + ∑ b = 1 n b Ω ( f b ) ,
where w i = ( 1 − k w ) / ( | y i | ν + ε ) + k w from Eq. (2); the worked example uses the illustrative floor k w = 0.15 , exponent ν = 1.75 and stabiliser ε = 10 − 6 (the scenario values are in Table 8Table 9). For the five example targets these weights are all w i ≈ 0.150 (the targets are large and similar), whereas a hypothetical desaturation to y i = 60 would raise that sample’s weight, up-weighting its contribution to the loss. Equation (30) is written here in the compact summary form used in the literature; the remainder of this subsection derives, step by step, how the trees that minimize it are actually built.

2.5.1. Training the Trees: Original XGBoost, and the Three Places Where Our Code Enters

The trees are trained by the gradient-boosting algorithm of XGBoost 2.1.4 exactly as released. We reproduce none of its derivations: the additive recursion is that of Friedman [48], and the second-order objective, the closed-form leaf score and the split gain are those of Chen and Guestrin [47], to which we refer for their proofs. We state only the four relations of that algorithm that our code touches, in the notation of this paper, so that each of our interventions can be located (Figure 2). Starting from the initial prediction y ^ 0 , i , each round adds one tree scaled by the learning rate η ; the tree of round b is fitted to the gradient and Hessian of the weighted squared loss at the previous prediction, summed over the training rows that its routing q b sends to leaf j; the leaf score and the gain of a split into children L and R follow in closed form with the penalties λ , α and γ :
y ^ b , i = y ^ b − 1 , i + η f b ( x i ) , b = 1 , … , n b ,
g b , i = w i ( y ^ b − 1 , i − y i ) , h b , i = w i ,
I b , j = { i : q b ( x i ) = j } ,
G b , j = ∑ i ∈ I b , j g b , i , H b , j = ∑ i ∈ I b , j h b , i ,
s b , j * = − T α ( G b , j ) H b , j + λ , T α ( G ) = sign ( G ) max ( | G | − α , 0 ) ,
Gain = 1 2 T α ( G b , L ) 2 H b , L + λ + T α ( G b , R ) 2 H b , R + λ − T α ( G b , L + G b , R ) 2 H b , L + H b , R + λ − γ ,
with I b , j the set of training rows in leaf j, s b , j * in %, G and α in %, H and λ dimensionless, and the gain and γ in % 2 ; a node is split while the gain is positive, both children keep a summed Hessian of at least min_child_weight and the depth is below max_depth, and otherwise it becomes a leaf with the score of Eq. (35). In the library, Eq. (32) is src/objective/regression_obj.cu, Eq. (35) is CalcWeight in src/tree/param.h, Eq. (36) is CalcGain applied inside EnumerateSplit in src/tree/hist/evaluate_splits.h, and the scaling by η of Eq. (31). Our code enters this algorithm at three places, all of them before the first tree is grown, and modifies nothing inside it. First, the starting value y ^ 0 , i of Eq. (31) is our anchor, the last available measurement in X0 and XP, Eq. (19), and the patient-level anchor of Eq. (20) inv4, passed as the base_margin of both matrices (utils_prediction.py) and copied by the library into the prediction buffer of every row before the first tree (Predictor::InitOutPredictions, src/predictor/predictor.cc); consequently every gradient of Eq. (32) is evaluated relative to the anchor, and every leaf score of Eq. (35) is a correction to it rather than to a constant. Second, the weights w i of Eq. (2), our relative-entropy criterion of Section 2.3, are the weight of the training matrix and multiply every gradient and Hessian (regression_obj.cu). Third, the hyperparameters η , λ , α , γ , max_depth, min_child_weight, the two subsampling ratios and the early-stopping patience are set per scenario (Table 8 and Table 9). The library’s evaluation of the validation rows after each round (src/learner.cc) sees the unblended y ^ b , i and chooses the number of trees n b by early stopping (Section 2.8.1): on average 792.4 trees per fold with 12.0 leaves each in X0 and XP, and 83.2 trees with 5.4 leaves in v4 (Table 10). After the last tree, the final prediction of Section 2.6 is formed; it is ours and is not part of the training. The reason the anchor changes what the trees learn is visible in Eq. (32): with the raw persistence anchor, the first gradients are the errors of a noisy nine-hour-old value, and the trees spend their capacity on pulling it toward the patient’s level, which appears as a negative variance share of the trees in Section 3.3; with the patient-level anchor that work is done in closed form before boosting, and a far smaller ensemble suffices.

2.6. The Final Prediction

The trees give the raw boosted estimate y ^ n b , i of Eq. (24). After the last tree, our C++ function ApplyAnchorBlend forms the final prediction y ˜ i (%) of every row, training and validation rows alike:
y ˜ i = y ^ 0 , i + ( 1 − β ) y ^ n b , i − y ^ 0 , i + β 1 cOUR i [ XP ]
where the dimensionless β ∈ [ 0 , 1 ] (custom_b) pulls the prediction toward its initial value and β 1 (% kg h−1 a.u.−1; custom_b1) weighs the cumulative oxygen uptake rate of Eq. (16): ( β , β 1 ) = ( 0 , 0 ) in X0, ( 0.1418 , 0.00139 ) in XP (config.py) and ( 0.3677 , 0.00124 ) in v4 (locked configuration file). Substituting Eq. (24), which gives y ^ n b , i − y ^ 0 , i = η ∑ b f b ( x i ) , together with Eqs. (20) and (16), into Eq. (37) writes the prediction of v4 in its original quantities:
y ˜ i = c 0 + c 1 y ( τ i ) + c 2 y ¯ H i ︸ y ^ 0 , i + ( 1 − β ) η ∑ b = 1 n b f b ( x i ) + β 1 D m i k g 1 | L i | ∑ ℓ ∈ L i OUR ( t i − ℓ ) [ v 4 ]
In X0 and XP the first term is y ( τ i ) , Eq. (19). Table 6 gives, for every term of Eq. (38), the Python variable that holds it, how it reaches src/learner.cc, where it is read and when it is used.
Table 6. The terms of Eq. (38) in the code. File utils_prediction.py unless stated; C++ lines in src/learner.cc.
Table 6. The terms of Eq. (38) in the code. File utils_prediction.py unless stated; C++ lines in src/learner.cc.
Term Python In C++ Used in
c 0 , c 1 , c 2 coef[0..2]; not present; they act through y ^ 0 , i through y ^ 0 , i
y ( τ i ) , y ¯ H i columns SaO2m_lag_9h, runmean_SaO2m not present through y ^ 0 , i
y ^ 0 , i raw_base_train, raw_base_val; base_margin base_margin_: start of the prediction buffer before the first tree; anchor training rounds, early stopping, prediction
η ∑ b f b ( x i ) the trees, trained by xgb.train PredictRaw (training), (early stopping),(prediction) training rounds, early stopping, prediction
cOUR i raw_int_train, raw_int_val;set_float_info("custom_integral",...), our field custom_integral_ (declared in include/xgboost/data.h; filled by MetaInfo::SetInfo, src/data/data.cc; C API src/c_api/c_api.cc) prediction
β , β 1 params["custom_b"], params["custom_b1"]; xgb.train(params=params, ...) tparam_.custom_b, tparam_.custom_b1 prediction
The predicted saturation is formed in Predict: PredictRaw evaluates the trees from y ^ 0 , i and gives y ^ n b , i , and ApplyAnchorBlend overwrites it in place with y ˜ i . Python receives y ˜ i from bst.predict(dval) for the validation rows, which are the reported out-of-fold predictions, and from bst.predict(dtrain) for the training rows. β and β 1 therefore act on the predictions of training and validation rows alike, but not on the training loss or the early-stopping criterion: UpdateOneIter and EvalOneIter never call ApplyAnchorBlend. For β ∈ [ 0 , 1 ] and β 1 = 0 , Eq. (37) is the convex combination ( 1 − β ) y ^ n b , i + β y ^ 0 , i , hence by the triangle inequality
| y ˜ i − y i | ≤ ( 1 − β ) | y ^ n b , i − y i | + β | y ^ 0 , i − y i | ≤ max | y ^ n b , i − y i | , | y ^ 0 , i − y i | ,
which is why custom_b is declared on [ 0 , 1 ] and why Eq. (37) is applied once, after the last tree: applied once per boosting round it would compound to ( 1 − β ) n b and Eq. (39) would not hold.
Preprints 236351 i005

2.7. Anatomy of a Prediction: How Much Is Physics and How Much Is Trees

Eq. (38) splits every final prediction exactly into three parts, written next to every out-of-fold row by the pipeline (anchorpart, treepart, integralpart; utilsprediction.py):
y ˜ i = A i + B i + C i , A i = y ^ 0 , i , B i = ( 1 − β ) η ∑ b = 1 n b f b ( x i ) , C i = β 1 cOUR i ,
all in %. For each part X ∈ { A , B , C } the variance share and the work share are
variance share ( X ) = Cov ( X , y ˜ ) Var ( y ˜ ) , work share ( X ) = | X − X 0 | ¯ ∑ X ′ | X ′ − X ′ 0 | ¯ ,
with X 0 = y ( τ i ) for A and X 0 = 0 for B and C, and the error credit of the anchor is
error credit = MAPE ( y ( τ ) ) − MAPE ( y ^ 0 ) MAPE ( y ( τ ) ) − MAPE ( y ˜ ) ,
with MAPE as in Eq. (43). By bilinearity of the covariance, substituting Eq. (40) into Eq. (41) gives Cov ( A , y ˜ ) + Cov ( B , y ˜ ) + Cov ( C , y ˜ ) = Var ( y ˜ ) , so the three variance shares sum to 100%; a negative share means that the part moves against the prediction. The work share says how far each part moves the prediction away from the last available measurement, and the error credit which fraction of the improvement over it the anchor earns before any tree is grown.

2.8. Training and Evaluation Strategy

To avoid overly optimistic performance estimates caused by temporal correlation within the same patient trajectory, we implemented a 5-fold Grouped Cross-Validation strategy. In this configuration, data is partitioned such that all samples of a patient are kept together within a single fold. This ensures that no data from the same patient used during the training phase is ever present in the test set, effectively preventing data leakage. The patient-level fold assignment is shuffled with a fixed random seed (random_state  = 42 ), which also seeds the XGBoost estimator, so that the entire pipeline is reproducible; every scenario uses the same folds.

Target-history leakage and the strict gap.

Because two of the inputs are the target’s own past values ( S a O 2 m at t − 9 and t − 10 ), the validity of the reported error depends critically on which target lags are admitted as features. The blood-gas measurement that defines S a O 2 m is itself delayed by roughly nine hours, so at deployment the freshest genuinely available value of the target is its 9-hour lag; any value of S a O 2 m from the intervening eight hours ( t − 1 , … , t − 8 ), and any feature derived from future samples, would simply not exist at prediction time. If such a near-past or future value of the target were allowed into the feature set, the model would in effect be shown a lightly time-shifted copy of the answer: the reported MAPE would collapse to an optimistically small figure, and the “virtual sensor” would be quietly reading the very signal it is meant to reconstruct rather than inferring it from ventilator and gas measurements. The pipeline constructs only target lags of nine hours or more. It does not, however, discard the rows that lack a nine-hour lag: in the first nine hours of a stay it fills the lag with the patient’s first measurement (fallback_to_first=True), and SaO2m_first and the patient mean carry the same value, so these 287 rows ( 7.1 % ) see a value fresher than t − 9 , and 33 of them the current target itself. By the rule above these rows are invalid; all results of Section 3 are computed without them, so that the estimator at hour t sees the real-time gas and ventilator channels plus target history no fresher than t − 9 . It is important to stress that the patient-grouped cross-validation above does not on its own guard against this particular failure: grouping by patient eliminates between-patient leakage, but a near-past or future copy of a patient’s own target leaks within that patient’s trajectory, which grouped folds cannot detect. The headline accuracy must therefore be read as conditional on the strict-gap construction; relaxing it, admitting sub-gap target lags, or back-filling missing values from later rows, would lower the apparent error without any gain in genuine predictive power, and any such configuration should be treated as invalid for the nine-hour-ahead claim.
The primary evaluation metric utilized in this study is the Mean Absolute Percentage Error (MAPE), as it provides a relative measure of error that is clinically informative across varying oxygenation levels. The MAPE is defined as:
MAPE = 100 % n i ∑ i = 1 n i y i − y ^ i y i
Equation (43) is the pooled, row-weighted MAPE. Three patients (18, 3 and 21) hold about 85% of the squared error of every scenario, and five patients have hours with two readings, so the pooled MAPE mostly reports those patients. We therefore report, for every scenario, the per-patient MAPE
MAPE p = 100 % n i , p ∑ i : p ( i ) = p y i − y ˜ i y i
and three summaries of it over the n p = 31 patients: the macro MAPE, its mean; the trimmed MAPE, its mean without the three worst patients; and its median. The macro MAPE is the objective that the pruning and the tuning of v4 used. Tracking within a patient is measured by
R within , p 2 = 1 − 1 n i , p ∑ i : p ( i ) = p ( y i − y ˜ i ) 2 Var p ( y ) ,
which is positive only when the model beats the patient’s own mean; its median over patients is reported together with the same quantity computed for persistence, the floor a virtual sensor must beat, and with the number of patients in which the model beats persistence. The pooled Pearson correlation r between y ˜ and y is reported as in our earlier work, with the caveat that it is lifted by between-patient level differences.

2.8.1. Training Rows and Validation Rows

In each fold the rows of 24 or 25 patients are training rows and the rows of the other 6 or 7 patients are validation rows; the reported predictions are those of the validation rows. Table 7 lists every place where the two are treated differently.
Two consequences follow. The training loss and the early-stopping criterion never see β and β 1 : the blend of Eq. (37) exists only at prediction time. And the validation rows choose n b through early stopping, so they are not entirely unseen during training; the folds are identical in every scenario, so the comparison between scenarios is not affected.
Hyperparameters of each scenario.
X0 and XP use the configured operating point of our pipeline (config.py; Table 8); X0 differs from XP only in β = β 1 = 0 . The hyperparameters of v4 (Table 9) were selected by a tree-structured Parzen estimator search (Optuna [49]) on the same patient-grouped folds for the 19-input tree with an earlier anchor, and were kept unchanged when the anchor of Eq. (20) was introduced; v4 itself was not re-tuned. Its lag lists (Table 1) were reduced from those of X0 and XP by lag-group ablation on the same folds; the column O2diffxPower is hidden from its trees because it feeds Eq. (16), and Svoris was hidden by a knockout test on the same folds. The configuration is fixed in the locked configuration file (Section 2.8.1.2).
Table 7. What differs between training and validation rows within a fold. File and line refer to the delivered sources.
Table 7. What differs between training and validation rows within a fold. File and line refer to the delivered sources.
Step Training rows Validation rows Code
standardisation of the tree inputs scaler fitted and applied training scaler applied data_preparation.py
y ( τ i ) , y ¯ H i , cOUR i from the row’s own past the same formula data_preparation.py
anchor coefficients, Eq. (21) fitted applied, not fitted utils_prediction.py
sample weights w i in the loss none utils_prediction.py
trees f b fitted to the gradients not used for fitting utils_prediction.py
y ^ b , i after each round enters the gradients enters the early-stopping RMSE, unweighted and without the blend learner.cc
number of trees n b — decided by early stopping utils_prediction.py
final prediction, Eq. (37) computed computed; reported out of fold learner.cc
Table 8. Hyperparameters of X0 and XP (config.py and the TrainConfig block). X0 sets β = β 1 = 0 ; everything else is identical.
Table 8. Hyperparameters of X0 and XP (config.py and the TrainConfig block). X0 sets β = β 1 = 0 ; everything else is identical.
Parameter (name in the code) Value Role
learning_rate ( η ) 0.0150 step applied to each tree’s correction, Eq. (31)
n_estimators ( n b cap) 2000 ceiling on the tree count; early stopping selects 792.4 on average
early_stopping_rounds 100 rounds without validation improvement before halting
max_depth 4 maximum tree depth
min_child_weight 0.632 minimum summed Hessian per leaf (the IsValid guard)
reg_lambda ( λ ) 17.17 L 2 penalty on leaf scores, Eq. (35)
reg_alpha ( α ) 0.328 L 1 penalty on leaf scores
gamma ( γ ) 0 minimum gain to accept a split
subsample 0.505 fraction of rows per tree
colsample_bytree 1.0 fraction of columns per tree
tree_method hist histogram split finding
custom_b ( β ) 0 (X0) / 0.1418 (XP) anchor blend, Eq. (37)
custom_b1 ( β 1 ) 0 (X0) / 0.00139 (XP) integral weight, Eq. (37)
custom_power ( ν ), custom_kp ( k w ) 3.656 , 0.148 cost weights, Eq. (2); inert on this target range (Section 3.5)
random_state 42 fold shuffle and model seed
Table 9. Hyperparameters of v4 (locked configuration file locked_model_v4.json, keys xgb_params, train and runtime), selected by the search described in the text.
Table 9. Hyperparameters of v4 (locked configuration file locked_model_v4.json, keys xgb_params, train and runtime), selected by the search described in the text.
Parameter (name in the code) Value Role
learning_rate ( η ) 0.0986 step applied to each tree’s correction
n_estimators ( n b cap) 2000 ceiling; early stopping selects 83.2 trees on average
early_stopping_rounds 50 patience
max_depth 3 maximum tree depth
min_child_weight 97.96 minimum summed Hessian per leaf
reg_lambda ( λ ) 59.61 L 2 penalty on leaf scores
reg_alpha ( α ) 11.19 L 1 penalty on leaf scores
subsample, colsample_bytree 0.975 , 0.927 row and column fractions per tree
custom_b ( β ) 0.3677 anchor blend, Eq. (37)
custom_b1 ( β 1 ) 0.00124 integral weight, Eq. (37)
mass_balance=calib_pt — the anchor of Eq. (20), fitted per fold
tree_exclude O2diffxPower, Svoris columns hidden from the trees
custom_power ( ν ), custom_kp ( k w ) 9.174 , 0.928 cost weights; inert (Section 3.5)
Reproducibility.
Each scenario is fully specified by one configuration: X0 and XP by config.py with β = β 1 = 0 or with their configured values, and v4 by a locked JSON file that records its lag lists, the columns hidden from the trees, the anchor mode and every hyperparameter; XGB_LOCKED=<file> python train.py re-trains it and reproduces the metrics of Section 3 exactly (same folds, same seed). The three scenarios were evaluated in one run on identical folds, and the out-of-fold prediction of every row was stored together with its three parts of Eq. (40).

3. Results

All results are out-of-fold predictions under the patient-grouped five-fold cross-validation of Section 2.8, with identical folds for the three scenarios. Following the rule of Section 2.8, they are scored on the 3730 rows of 30 patients whose inputs contain no S a O 2 m value younger than nine hours (Section 3.7); the values on all 4017 rows are listed alongside in Table 14. A patient counts as beating persistence when its R within , p 2 , Eq. (45), exceeds that of y ( τ i ) .

3.1. Accuracy and Size of the Three Scenarios

Table 10 reports accuracy and size. The C++ terms of XP lower the macro MAPE by 0.032 percentage points: a paired patient bootstrap of XP − X0 (2000 resamples of the 30 patients) gives − 0.032 with 95% interval [ − 0.065 , − 0.001 ] , while the intervals of the pooled ( − 0.010 , [ − 0.055 , + 0.027 ] ), trimmed ( − 0.027 , [ − 0.058 , + 0.001 ] ) and median per-patient MAPE ( − 0.060 , [ − 0.206 , + 0.053 ] ) include zero; 17 of the 30 patients improve. The effect of XP is therefore small and resolved only for the mean per-patient error. The patient-level anchor of v4 lowers, relative to XP, the pooled MAPE by 0.163 ( [ − 0.280 , − 0.021 ] ), the macro MAPE by 0.172 ( [ − 0.281 , − 0.056 ] ) and the trimmed MAPE by 0.142 ( [ − 0.241 , − 0.027 ] ), while the change of the median, − 0.073 ( [ − 0.329 , + 0.125 ] ), is not resolved; 22 of the 30 patients improve. v4 raises the pooled correlation from 0.754 to 0.793 and the median within-patient R 2 from − 0.417 to − 0.164 , beats persistence in 29 of the 30 patients, and does so with 19 inputs instead of 55, 83 trees instead of 792 and 450 leaves per fold instead of 9527. Keeping only the last of two readings in the same hour (3427 strict rows) changes the pooled MAPE to 3.919% (X0), 3.898% (XP) and 3.741% (v4) and leaves the ranking unchanged.
Table 10. Out-of-fold accuracy and size on the 3730 rows of 30 patients whose inputs contain no S a O 2 m value younger than nine hours; identical patient-grouped folds. Trees and leaves are per-fold means. The persistence column scores y ( τ i ) itself, with no model.
Table 10. Out-of-fold accuracy and size on the 3730 rows of 30 patients whose inputs contain no S a O 2 m value younger than nine hours; identical patient-grouped folds. Trees and leaves are per-fold means. The persistence column scores y ( τ i ) itself, with no model.
Quantity Persistence X0 XP v4
tree inputs n m — 55 55 19
trees per fold — 792.4 792.4 83.2
leaves per fold — 9527.4 9527.4 450.2
pooled MAPE (%) 4.308 3.900 3.890 3.727
macro MAPE (%) 3.499 3.321 3.289 3.117
trimmed MAPE (%) 2.038 1.878 1.850 1.709
median per-patient MAPE (%) 1.982 1.875 1.815 1.742
pooled Pearson r 0.728 0.754 0.754 0.793
median R within 2 − 0.800 − 0.427 − 0.417 − 0 . 164
patients beating persistence (of 30) — 27 27 29

3.2. The Anchor Coefficients of v4

Table 11 lists the coefficients of Eq. (20) fitted on each training fold. c 1 and c 2 keep their sign in every fold, and their sum is 0.964 on average, so the anchor is, to four per cent, a weighted average that gives the nine-hour-old measurement 26 % of the weight and the patient’s own history 74 % ; the intercept is small and changes sign across folds. The anchor alone, before any tree, has a pooled MAPE of 3.695 % against 4.130 % for the persistence value it recalibrates.
Table 11. Coefficients of the v4 anchor, Eq. (20), per training fold (locked configuration file, key anchor_coefficients_per_fold).
Table 11. Coefficients of the v4 anchor, Eq. (20), per training fold (locked configuration file, key anchor_coefficients_per_fold).
Fold c 0 c 1 (last measurement) c 2 (patient history) c 1 + c 2
1 9.325 0.2429 0.6585 0.901
2 2.252 0.2531 0.7223 0.975
3 5.636 0.3056 0.6378 0.943
4 − 2.883 0.1933 0.8350 1.028
5 2.508 0.2412 0.7313 0.972
mean 3.368 0.2472 0.7170 0.964

3.3. How Much of Each Prediction Is Physics

Table 12 applies the shares of Section 2.7 to the strict rows. In X0 and XP the anchor is the raw persistence value and the trees’ variance share is negative ( − 13.7 % , − 13.1 % ): the trees pull the noisy nine-hour-old value toward the patient’s level, which is the shrinkage of Eq. (22) done split by split with 792 trees. In v4 the anchor of Eq. (20) does this in closed form: alone it lowers the pooled MAPE from 4.308% (persistence) to 3.836%, which is 81% of the improvement of the full model (3.727%), it does 71% of the work, and the 83-tree ensemble corrects single rows while adding 1% of the variance. On the median patient the trees add nothing: the anchor alone has a median per-patient MAPE of 1.703%, the full v4 model 1.742%. The identity y ˜ i = A i + B i + C i holds to 4 × 10 − 6 on every row.
Table 12. Shares of Eqs. (41)–(42) in per cent on the strict rows. The variance shares of the three parts sum to 100.
Table 12. Shares of Eqs. (41)–(42) in per cent on the strict rows. The variance shares of the three parts sum to 100.
Share (%) X0 XP v4
variance share of the anchor A 113.65 113.99 99.94
variance share of the trees B − 13.65 − 13.11 1.02
variance share of the cumulative OUR term C 0.00 − 0.88 − 0.97
work share of the anchor A 0.00 0.00 71.33
work share of the trees B 100.00 84.76 20.44
work share of the cumulative OUR term C 0.00 15.24 8.23
error credit of the anchor 0.00 0.00 81.27
pooled MAPE of the anchor alone (%) 4.308 4.308 3.836

3.4. Ablation of the Two C++ Coefficients in v4

Table 13 evaluates the trained v4 model with β , β 1 or both set to zero in Eq. (37). The two coefficients act only on the predictions (Section 2.6), so the trees are the same in every row of the table, and each row measures what a coefficient contributes to the predictions of the validation rows. The predictions with a coefficient set to zero are not stored row by row, so the table is on all 4017 rows. Setting β = 0 raises the pooled MAPE by 0.032 percentage points, the trimmed by 0.027 and the median by 0.061; setting β 1 = 0 raises the pooled, macro and trimmed MAPE by about 0.004 and lowers the median by 0.025. Both coefficients are kept by our rule that a physics coefficient is set to zero only when doing so changes the median per-patient MAPE by at most 0.001 and the macro by at most 0.005.
Table 13. Change of each metric when a coefficient of Eq. (37) is set to zero in the trained v4 model; all 4017 rows, percentage points.
Table 13. Change of each metric when a coefficient of Eq. (37) is set to zero in the trained v4 model; all 4017 rows, percentage points.
Set to zero Δ pooled Δ macro Δ trimmed Δ median
β 1 = 0 + 0.0043 + 0.0037 + 0.0041 − 0.0254
β = 0 + 0.0318 + 0.0071 + 0.0270 + 0.0614
β = β 1 = 0 + 0.0249 + 0.0027 + 0.0245 + 0.0038

3.5. The Cost Weights Are Inert

The recorded target ranges from 20 to 111 % (Section 2.1). Over all 4017 rows, the largest relative deviation of w i from k w in Eq. (2) is 1.0 × 10 − 4 in X0 and XP ( ν = 3.656 , k w = 0.148 ) and 9.0 × 10 − 14 in v4 ( ν = 9.174 , k w = 0.928 ), so the weights are constant to that precision and the weighted least squares of Eq. (21) and the weighted objective of the trees are unweighted in effect: the tuned values sit at the variance end of the trade-off of Eq. (5). The squared-relative-error end would matter only if ( 1 − k w ) / | y | ν were comparable with k w , which for y between 50 and 100 % requires k w of order 10 − 4 at p = 2 , below the range the tuning explored; exploring it is left for future work.

3.6. The Age of the Anchor and the Persistence Baseline

The persistence value is the most recent measurement at or before t i − 9 h, Eq. (17). Of the 4017 rows, 89.5 % have an anchor exactly nine hours old; 3.3 % have an older one (median age 22.0 h, 90th percentile 74.8 h, maximum 81 h) because no measurement fell in the preceding hour; and 7.1 % lie in the first nine hours of a stay and use the patient’s first measurement, whose age is below nine hours and is zero in 33 rows ( 0.8 % ): the first row of each patient and, for patients 2 and 3, a second reading in that same hour. Because the target is integer-valued, the nine-hour-old value equals the target exactly in 17.1 % of the rows; in the rows that have a measurement at least nine hours old this is quantisation of the label, not leakage, and it sets the floor that Table 10 reports for persistence.

3.7. Strict Nine-Hour Check

The target-derived inputs use S a O 2 m values younger than nine hours in one situation: when a patient has no measurement at or before t i − D , that is, in the first D hours of a stay. There y ( τ i ) and SaO2m_lag_10h fall back to the patient’s first measurement (data_preparation.py, called with fallback_to_first=True), y ¯ H i is filled with the same value (utils_prediction.py), and the tree input SaO2m_first is that first measurement too (data_preparation.py). This concerns 287 of the 4017 rows ( 7.1 % ) in every scenario, and in 33 of them the value used is the current target itself; one patient has no row outside this window, so the strict rows cover 30 patients. No value from a later hour is used anywhere: the lags are taken with a backward merge, the patient mean stops at t i − D , and SaO2m_first is the earliest reading. Because the validation patients of a fold never appear among its training patients, these inputs in training rows carry no information about the validation rows; removing the 287 rows at scoring therefore leaves out-of-fold predictions whose inputs contain no S a O 2 m value younger than nine hours. Table 14 compares the two evaluations.
Table 14. Out-of-fold metrics on all 4017 rows (31 patients) and on the 3730 strict rows (30 patients).
Table 14. Out-of-fold metrics on all 4017 rows (31 patients) and on the 3730 strict rows (30 patients).
X0 XP v4
Metric all strict all strict all strict
pooled MAPE (%) 3.791 3.900 3.766 3.890 3.603 3.727
macro MAPE (%) 3.272 3.321 3.209 3.289 3.029 3.117
trimmed MAPE (%) 1.962 1.878 1.906 1.850 1.758 1.709
median per-patient MAPE (%) 1.936 1.875 1.850 1.815 1.737 1.742
pooled Pearson r 0.763 0.754 0.764 0.754 0.801 0.793
The ranking of the three scenarios is the same in both evaluations. A deployable sensor under the strict rule starts nine hours after a patient’s first measurement; rows before that point would need a population prior as the anchor, which is not part of this study.

4. Discussion

Three findings carry the paper, all measured on the rows whose inputs contain no S a O 2 m value younger than nine hours. First, the physics pays through the anchor. The patient-level recalibration of v4 is a two-coefficient linear term, yet on its own it earns 81% of the improvement over persistence, and with it the pooled, macro and trimmed errors fall by 0.14 to 0.17 percentage points relative to XP, with bootstrap intervals that exclude zero, while the tree ensemble shrinks to 19 inputs and 450 leaves. Second, the anatomy of Table 12 explains why: with a raw persistence anchor the trees spend a negative variance share on shrinking a noisy measurement toward the patient’s level, a task that Eq. (22) performs in closed form once the patient’s own history is available; freed from it, a much smaller ensemble corrects single rows. Third, the direct contribution of the gas signals through the physics terms is small: the cumulative oxygen uptake rate and the blend of XP lower the mean per-patient error by 0.032 percentage points, an effect whose interval only just excludes zero and which the pooled, trimmed and median summaries do not resolve.
What the sensor does and does not do is now explicit. It reproduces each patient’s level and beats the last blood gas in 29 of 30 patients; it does not resolve hourly changes for typical patients, whose hourly standard deviation of about 1.9 percentage points is at the label’s integer quantisation, and the median within-patient R 2 stays negative in all scenarios. The median per-patient error is not resolved by either step, and on the median patient the anchor of v4 alone is as accurate as the full model.
The claims are bounded by the design. The cohort is small (30 patients on the strict rows), and three patients hold most of the squared error, which is why the macro, trimmed and median per-patient errors are reported next to the pooled one and every difference is tested with a paired patient bootstrap. The validation rows decide the number of trees through early stopping, which is common to all scenarios and therefore does not favour one of them. The training rows still include the first nine hours of the training patients’ stays; this carries no information about the validation patients, but a pipeline that drops these rows from training as well would be the natural next version.
Within the scope of this Special Issue, the model is a multivariate time-series application with an explicit account of what each component contributes, and its loss is the relative-entropy criterion of our earlier estimators; a natural next step is to add information-theoretic descriptors of the ventilator channels (permutation or sample entropy over the same lag windows) as tree inputs and to test whether they carry the within-patient dynamics that the present inputs do not.

5. Conclusions

A virtual sensor for arterial oxygen saturation across a nine-hour blood-gas gap was built as three nested scenarios of one code base and evaluated on identical folds on the rows whose inputs contain no saturation value younger than nine hours. Adding to XGBoost 2.1.4 a blend toward the anchor and the cumulative oxygen uptake rate over the gap, derived from an oxygen balance of the arterial blood (XP), gives a small improvement of the mean per-patient error. Replacing the raw nine-hour-old measurement by a patient-level calibrated anchor (v4) lowers the pooled, macro and trimmed errors with bootstrap intervals that exclude zero, beats the last blood gas in 29 of 30 patients, and reduces the ensemble to 19 inputs and 450 leaves; the anchor alone earns 81% of the gain over persistence. Every equation is matched to the line of C++ or Python that implements it, and each scenario is reproducible from one configuration file.

Author Contributions

Conceptualization, R.U.; methodology, R.U., S.R. and V.Ga.; software, R.U. and N.P.; validation, R.U., N.P. and V.Ga.; formal analysis, R.U. and N.P.; investigation, R.U. and N.P.; resources, R.U and V.Ga.; data curation, R.U. and T.K.; writing—original draft preparation, R.U. and N.P.; writing—review and editing, R.U., N.P. and V.Ga.; visualization, R.U. and N.P.; supervision, R.U., L.J. and V.Ga.; project administration, R.U., V.Ga. and V.Gu.; funding acquisition, V.Ga All authors have read and agreed to the published version of the manuscript.

Funding

This research is funded by the Research Council of Lithuania (Grant No. S-ITP-25-1).

Institutional Review Board Statement

The medical study for collecting engineering data is carried out under the permit BE-2-92 granted by the Kaunas Regional Biomedical Research Ethics Committee.

Data Availability Statement

The changes to XGBoost 2.1.4 (src/learner.cc, and the field custom_integral in include/xgboost/data.h, src/data/data.cc and src/c_api/c_api.cc) are available from the corresponding author on reasonable request. The key functions of the Python pipeline are given in the listings of this paper. The patient data are not publicly available for privacy reasons.

Acknowledgments

The authors thank the Lithuanian University of Health Sciences Hospital Kauno Klinikos (Kaunas, Lithuania) for the collaboration in the pending clinical trials. During the preparation of this manuscript, the authors used Open AI models for the purpose of language editing and assistance in drafting text. The authors reviewed and edited the content as needed and take full responsibility for the content of the publication.

Conflicts of Interest

The authors declare no conflicts of interest.

Abbreviations

The following abbreviations are used in this manuscript:
S a O 2 m arterial oxygen saturation measured by co-oximetry
MAPE mean absolute percentage error
OOF out of fold
PEEP positive end-expiratory pressure
OUR oxygen uptake rate
TPE tree-structured Parzen estimator

References

  1. Dall’Ora, C.; Saville, C.; Rubbo, B.; Turner, L.; Jones, J.; Griffiths, P. Nurse staffing levels and patient outcomes: A systematic review of longitudinal studies. Int. J. Nurs. Stud. 2022, 134, 104311. [Google Scholar] [CrossRef]
  2. Bertoni, M.; Spadaro, S.; Goligher, E.C. Monitoring Patient Respiratory Effort During Mechanical Ventilation: Lung and Diaphragm-Protective Ventilation. Crit. Care 2020, 24, 106. [Google Scholar] [CrossRef]
  3. Nguyen, L.S.; Squara, P. Non-invasive monitoring of cardiac output in critical care medicine. Front. Med. 2017, 4. [Google Scholar] [CrossRef]
  4. Athaya, T.; Choi, S. A Review of Noninvasive Methodologies to Estimate the Blood Pressure Waveform. Sensors 2022, 22. [Google Scholar] [CrossRef]
  5. Dong, J.; Xu-Wilson, M.; Conroy, B.R.; Khemani, R.G.; Newth, C.J.L. Continuous noninvasive blood gas estimation in critically ill pediatric patients with respiratory failure. Sci. Rep. 2022, 12. [Google Scholar] [CrossRef]
  6. Krzych, L.; Wojnarowicz, O.; Ignacy, P.; Dorniak, J. Be cautious during the interpretation of arterial blood gas analysis performed outside the intensive care unit. Acta Biochim. Pol. 2020, 67, 353–358. [Google Scholar] [CrossRef]
  7. Patharkar, A.; Cai, F.; Al-Hindawi, F.; Wu, T. Predictive modeling of biomedical temporal data in healthcare applications: review and future directions. Front. Physiol. 2024, 15. [Google Scholar] [CrossRef]
  8. Lee, J.M.; Hauskrecht, M. Modeling multivariate clinical event time-series with recurrent temporal mechanisms. Artif. Intell. Med. 2021, 112. [Google Scholar] [CrossRef]
  9. Dauvin, A.; Donado, C.; Bachtiger, P.; Huang, K.C.; Sauer, C.M.; Ramazzotti, D.; Bonvini, M.; Celi, L.A.; Douglas, M.J. Machine learning can accurately predict pre-admission baseline hemoglobin and creatinine in intensive care patients. npj Digit. Med. 2019, 2. [Google Scholar] [CrossRef]
  10. Kipnis, E.; Ramsingh, D.; Bhargava, M.; Dincer, E.; Cannesson, M.; Broccard, A.; Vallet, B.; Bendjelid, K.; Thibault, R. Monitoring in the Intensive Care. Crit. Care Res. Pract. 2012, 2012, 473507. [Google Scholar] [CrossRef]
  11. Qiu, X.; Tan, X.; Wang, C.; Chen, S.; Du, B.; Huang, J. A long short-term memory relation network for real-time prediction of patient-specific ventilator parameters. Math. Biosci. Eng. 2023, 20, 14756–14776. [Google Scholar] [CrossRef]
  12. The Acute Respiratory Distress Syndrome Network.; Brower, R.G.; Matthay, M.A.; Morris, A.; Schoenfeld, D.; Thompson, B.T.; Wheeler, A. Ventilation with Lower Tidal Volumes as Compared with Traditional Tidal Volumes for Acute Lung Injury and the Acute Respiratory Distress Syndrome. N. Engl. J. Med. 2000, 342, 1301–1308. [Google Scholar] [CrossRef]
  13. Brower, R.G.; Lanken, P.N.; MacIntyre, N.; Matthay, M.A.; Morris, A.; Ancukiewicz, M.; Schoenfeld, D.; Thompson, B.T. National Heart, Lung, and Blood Institute ARDS Clinical Trials Network. Higher versus Lower Positive End-Expiratory Pressures in Patients with the Acute Respiratory Distress Syndrome. N. Engl. J. Med. 2004, 351, 327–336. [Google Scholar] [CrossRef]
  14. Zhang, L.; Ren, G.; Li, S.; Du, J.; Xu, D.; Li, Y. A novel soft sensor approach for industrial quality prediction based TCN with spatial and temporal attention. Chemom. Intell. Lab. Syst. 2025, 257. [Google Scholar] [CrossRef]
  15. Wang, C.; He, T.; Zhou, H.; Zhang, Z.; Lee, C. Artificial intelligence enhanced sensors - enabling technologies to next-generation healthcare and biomedical platform. Bioelectron. Med. 2023, 9, 17. [Google Scholar] [CrossRef]
  16. Li, J.; Ma, J.; Omisore, O.M.; Liu, Y.; Tang, H.; Ao, P.; Yan, Y.; Wang, L.; Nie, Z. Noninvasive Blood Glucose Monitoring Using Spatiotemporal ECG and PPG Feature Fusion and Weight-Based Choquet Integral Multimodel Approach. IEEE Trans. Neural Netw. Learn. Syst. 2024, 35, 14491–14505. [Google Scholar] [CrossRef]
  17. Quamer, W.; Tseng, M.R.; Vyas, K.; Dave, D.; Villegas, C.; McKay, S.; DeSalvo, D.J.; Erranguntla, M.; Cote, G.; Gutierrez-Osuna, R. A multimodal physiological dataset for non-invasive blood glucose estimation. Sci. Data 2025, 12. [Google Scholar] [CrossRef]
  18. Tsou, P.H.; Lin, Z.L.; Pan, Y.C.; Yang, H.C.; Chang, C.J.; Liang, S.K.; Wen, Y.F.; Chang, C.H.; Chang, L.Y.; Yu, K.L.; et al. Exploring volatile organic compounds in breath for high-accuracy prediction of lung cancer. Cancers 2021, 13, 1–14. [Google Scholar] [CrossRef]
  19. Choo, Y.J.; Lee, G.W.; Moon, J.S.; Chang, M.C. Application of non-contact sensors for health monitoring in hospitals: a narrative review. Front. Med. 2024, 11. [Google Scholar] [CrossRef]
  20. Nan, X.; Wang, X.; Kang, T.; Zhang, J.; Dong, L.; Dong, J.; Xia, P.; Wei, D. Review of Flexible Wearable Sensor Devices for Biomedical Application. Micromachines 2022, 13, 1395. [Google Scholar] [CrossRef]
  21. Moraes, F.M.D.; Silva, G.S. Noninvasive intracranial pressure monitoring methods: A critical review. Arq. De Neuro-Psiquiatr. 2021, 79, 437–446. [Google Scholar] [CrossRef]
  22. Wolber, J.; Schuppert, A.; Mücke, M.; Sellin, J. Predicting disease outcomes from remote monitoring using machine learning: a systematic review. BMC Med. Inform. Decis. Mak. 2026, 26. [Google Scholar] [CrossRef]
  23. Skarysz, A.; Salman, D.; Eddleston, M.; Sykora, M.; Hunsicker, E.; Nailon, W.H.; Darnley, K.; McLaren, D.B.; Thomas, C.L.P.; Soltoggio, A. Fast and automated biomarker detection in breath samples with machine learning. PLoS ONE 2022, 17. [Google Scholar] [CrossRef]
  24. Lee, A.R.; Lee, J.H.; Yoo, S.; Lee, H.Y.; Kim, H.H. Real-Time Estimation of Arterial Partial Pressure of Carbon Dioxide in Patients Undergoing General Anesthesia: Predictive Modeling Study. JMIR Med. Inform. 2025, 13. [Google Scholar] [CrossRef]
  25. Che, Z.; Purushotham, S.; Cho, K.; Sontag, D.; Liu, Y. Recurrent Neural Networks for Multivariate Time Series with Missing Values. Sci. Rep. 2018, 8, 6085. [Google Scholar] [CrossRef]
  26. Woo, J.W.; Stapleton, O.; Luo, J.; Chuang, C.C.; Su, Y.; Sankararaman, S.; Mukherjee, E.; Sivakumar, N.; Calligy, K.; Duffy, S.; et al. AI-Driven SaO2 prediction from pulse oximetry and electronic health records. BioData Min. 2025, 18. [Google Scholar] [CrossRef]
  27. Cabanas, A.M.; Martín-Escudero, P.; Pagán, J.; Mery, D. Technical and regulatory challenges in artificial intelligence-based pulse oximetry: a proposed development pipeline. Br. J. Anaesth. 2025, 134, 1295–1299. [Google Scholar] [CrossRef]
  28. Ghazal, S.; Sauthier, M.; Brossier, D.; Bouachir, W.; Jouvet, P.A.; Noumeir, R. Using machine learning models to predict oxygen saturation following ventilator support adjustment in critically ill children: A single center pilot study. PLoS ONE 2019, 14. [Google Scholar] [CrossRef]
  29. Hüser, M.; Lyu, X.; Faltys, M.; Pace, A.; Berger, D.; Hoche, M.; Hyland, S.L.; Yèche, H.; Burger, M.; Merz, T.M.; et al. RMS: a ML-based system for ICU respiratory monitoring and resource planning. npj Digit. Med. 2025, 8. [Google Scholar] [CrossRef]
  30. Si, T.; Song, Y.; Sun, P.; Xiao, J.; Zou, R.; Chen, Z. Non-contact SpO2 monitoring via multi-channel pulse signals from facial videos using machine learning. Mach. Vis. Appl. 2025, 36. [Google Scholar] [CrossRef]
  31. Urniezius, R.; Survyla, A.; Paulauskas, D.; Bumelis, V.A.; Galvanauskas, V. Generic estimator of biomass concentration for Escherichia coli and Saccharomyces cerevisiae fed-batch cultures based on cumulative oxygen consumption rate. Microb. Cell Fact. 2019, 18, 190. [Google Scholar] [CrossRef]
  32. Urniezius, R.; Survyla, A. Identification of Functional Bioprocess Model for Recombinant E. Coli Cultivation Process. Entropy 2019, 21, 1221. [Google Scholar] [CrossRef]
  33. Survyla, A.; Urniezius, R.; Vaitkus, V.; Levisauskas, D.; Jankauskaite, L.; Lukminaite, D.; Laucaityte, G. Noninvasive Continuous Tracking of Partial Pressure of Oxygen in Arterial Blood: Adapting Microorganisms Bioprocess Soft Sensor Technology for Holistic Analysis of Human Respiratory System. In Proceedings of the 2021 IEEE International Conference on Multisensor Fusion and Integration for Intelligent Systems (MFI), Karlsruhe, Germany, 2021; pp. 1–5. [Google Scholar] [CrossRef]
  34. Kemesis, B.; Urniezius, R.; Kondratas, T.; Jankauskaite, L.; Masaitis, D.; Babilius, P. Bridging Functional Model of Arterial Oxygen with Information of Venous Blood Gas: Validating Bioprocess Soft Sensor on Human Respiration. In Proceedings of the Intelligent and Safe Computer Systems in Control and Diagnostics; Kowalczuk, Z., Ed.; Cham, 2023; pp. 42–51. [Google Scholar]
  35. Urniezius, R.; Galvanauskas, V.; Survyla, A.; Simutis, R.; Levisauskas, D. From Physics to Bioengineering: Microbial Cultivation Process Design and Feeding Rate Control Based on Relative Entropy Using Nuisance Time. Entropy 2018, 20, 779. [Google Scholar] [CrossRef]
  36. Urniezius, R.; Petrauskas, R.; Vaitkus, V.; Karimov, J.; Brazauskas, K.; Repsyte, J.; Kacerauskiene, E.; Harms, T.; Dargiene, J.; Ezerskis, D. Enhancing Prediction by Incorporating Entropy Loss in Volatility Forecasting. Entropy 2025, 27, 806. [Google Scholar] [CrossRef]
  37. Garcia-Ochoa, F.; Gomez, E.; Santos, V.E.; Merchuk, J.C. Oxygen uptake rate in microbial processes: An overview. Biochem. Eng. J. 2010, 49, 289–307. [Google Scholar] [CrossRef]
  38. Collins, J.A.; Rudenski, A.; Gibson, J.; Howard, L.; O’Driscoll, R. Relating oxygen partial pressure, saturation and content: the haemoglobin–oxygen dissociation curve. Breathe 2015, 11, 194–201. [Google Scholar] [CrossRef]
  39. Nadler, S.B.; Hidalgo, J.U.; Bloch, T. Prediction of blood volume in normal human adults. Surgery 1962, 51, 224–232. [Google Scholar]
  40. Ferrannini, E. The Theoretical Bases of Indirect Calorimetry: A Review. Metabolism 1988, 37, 287–301. [Google Scholar] [CrossRef]
  41. Rubin, D.B. Inference and Missing Data. Biometrika 1976, 63, 581–592. [Google Scholar] [CrossRef]
  42. Burden, R.L.; Faires, J.D. Numerical Analysis, 9th ed.; Brooks/Cole, Cengage Learning: Boston, MA, USA, 2011. [Google Scholar]
  43. Spearman, C. The Proof and Measurement of Association between Two Things. Am. J. Psychol. 1904, 15, 72–101. [Google Scholar] [CrossRef]
  44. Fuller, W.A. Measurement Error Models; John Wiley & Sons: New York, NY, USA, 1987. [Google Scholar] [CrossRef]
  45. Efron, B.; Morris, C. Data Analysis Using Stein’s Estimator and Its Generalizations. J. Am. Stat. Assoc. 1975, 70, 311–319. [Google Scholar] [CrossRef]
  46. Freund, Y.; Schapire, R.E. A Decision-Theoretic Generalization of On-Line Learning and an Application to Boosting. J. Comput. Syst. Sci. 1997, 55, 119–139. [Google Scholar] [CrossRef]
  47. Chen, T.; Guestrin, C. XGBoost: A Scalable Tree Boosting System. In Proceedings of the Proceedings of the 22nd ACM SIGKDD International Conference on Knowledge Discovery and Data Mining, New York, NY, USA, 2016; pp. 785–794. [Google Scholar] [CrossRef]
  48. Friedman, J.H. Greedy Function Approximation: A Gradient Boosting Machine. Ann. Stat. 2001, 29, 1189–1232. [Google Scholar] [CrossRef]
  49. Akiba, T.; Sano, S.; Yanase, T.; Ohta, T.; Koyama, M. Optuna: A Next-Generation Hyperparameter Optimization Framework. In Proceedings of the Proceedings of the 25th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining, New York, NY, USA, 2019; pp. 2623–2631. [Google Scholar] [CrossRef]
1
Every line number of XGBoost cited in this paper refers to the release 2.1.4 files of the library we patched and ran.
Figure 2. The boosting loop and where our code enters it (UML activity diagram). Grey blocks are original XGBoost 2.1.4 [47]; blocks with a black frame are ours, present in all three scenarios; the bold line of the Anchor block is v4 only. Our code sets the starting value y ^ 0 , i (the anchor), the weights w i and the cumulative oxygen uptake rate cOUR i before the loop and forms the final prediction after it; the loop, the tree recursion and the early stopping are unchanged. Every block cites its equation and the source functions of release 2.1.4.
Figure 2. The boosting loop and where our code enters it (UML activity diagram). Grey blocks are original XGBoost 2.1.4 [47]; blocks with a black frame are ours, present in all three scenarios; the bold line of the Anchor block is v4 only. Our code sets the starting value y ^ 0 , i (the anchor), the weights w i and the cumulative oxygen uptake rate cOUR i before the loop and forms the final prediction after it; the loop, the tree recursion and the early stopping are unchanged. Every block cites its equation and the source functions of release 2.1.4.
Preprints 236351 g002
Disclaimer/Publisher’s Note: The statements, opinions and data contained in all publications are solely those of the individual author(s) and contributor(s) and not of MDPI and/or the editor(s). MDPI and/or the editor(s) disclaim responsibility for any injury to people or property resulting from any ideas, methods, instructions or products referred to in the content.
Copyright: This open access article is published under a Creative Commons CC BY 4.0 license, which permit the free download, distribution, and reuse, provided that the author and preprint are cited in any reuse.