Predicting Severe Acute Respiratory Illness (SARI) Mortality with Scikit-Learn Halving Search A developer built an end-to-end Scikit-Learn pipeline to predict mortality versus recovery for Severe Acute Respiratory Illness (SARI) patients using over 260,000 Brazilian DataSUS records from 2025. The pipeline reads selected columns from Parquet files, normalizes comorbidities to binary flags, applies a stratified train-test split to handle roughly 8% mortality imbalance, and tunes a Random Forest with HalvingRandomSearchCV successive halving instead of exhaustive grid search. When dealing with public health data, computational efficiency and rapid experimentation are critical factors. In this tutorial, we will build an end-to-end Machine Learning pipeline using Python and Scikit-Learn to predict the clinical outcome of patients notified with Severe Acute Respiratory Illness SARI/SRAG in Brazil. We will work with a large-scale real-world dataset from DataSUS, clean and preprocess clinical features, handle class imbalance, and use an efficient search strategy called Successive Halving to optimize our Random Forest hyperparameters in a fraction of the time required by exhaustive Grid Search. Severe Acute Respiratory Illness SARI remains a major global public health concern. Predicting patient outcomes Recovery vs. Death based on initial demographics, symptoms, and comorbidities assists healthcare managers in risk stratification and resource allocation. Our dataset contains over 260,000 patient records from 2025 in Brazil. We will focus on key variables such as: CS SEXO and Age NU IDADE N . UTI and Ventilatory support SUPORT VEN . Because raw public health datasets contain dozens of unused epidemiological columns, reading uncompressed CSVs consumes excessive memory. We use the Apache Parquet format to enable columnar selection and fast I/O: python import pandas as pd import numpy as np file path = 'INFLUD25-data.parquet' target columns = 'CS SEXO', 'NU IDADE N', 'EVOLUCAO', 'UTI', 'SUPORT VEN', 'CARDIOPATI', 'DIABETES', 'OBESIDADE', 'RENAL', 'ASMA', 'IMUNODEPRE' df = pd.read parquet file path, columns=target columns print f"Dataset Dimensions: {df.shape}" Public health records contain ambiguous missing flags. We filter out unknown outcomes to build our binary target TARGET , where: 0 = Recovery Cura 1 = Mortality Óbito We then normalize categorical comorbidity features into strict binary 1 = Yes, 0 = No/Unknown values: Filter valid clinical endpoints df 'EVOLUCAO' = pd.to numeric df 'EVOLUCAO' , errors='coerce' df clean = df df 'EVOLUCAO' .isin 1, 2 .copy df clean 'TARGET' = df clean 'EVOLUCAO' .map {1: 0, 2: 1} df clean = df clean.drop 'EVOLUCAO', axis=1 Normalize clinical risk factors to binary comorbidity cols = 'UTI', 'SUPORT VEN', 'CARDIOPATI', 'DIABETES', 'OBESIDADE', 'RENAL', 'ASMA', 'IMUNODEPRE' for col in comorbidity cols: df clean col = pd.to numeric df clean col , errors='coerce' df clean col = df clean col .apply lambda x: 1 if x == 1 else 0 Impute and clean demographics df clean 'NU IDADE N' = pd.to numeric df clean 'NU IDADE N' , errors='coerce' df clean 'NU IDADE N' = df clean 'NU IDADE N' .fillna df clean 'NU IDADE N' .median df clean 'CS SEXO' = df clean 'CS SEXO' .map {'M': 0, 'F': 1, 'm': 0, 'f': 1} .fillna 0 Because mortality is an imbalanced class ~8% positive occurrences , standard random partitioning can cause class distribution drift. We apply a stratified split: python from sklearn.model selection import train test split X = df clean.drop 'TARGET', axis=1 y = df clean 'TARGET' X train, X test, y train, y test = train test split X, y, test size=0.3, random state=42, stratify=y Traditional GridSearchCV evaluates every parameter combination across the entire training dataset. For large datasets, this approach is computationally prohibitive. Instead, we use Successive Halving via HalvingRandomSearchCV : factor=3 , and surviving models are re-evaluated. python from sklearn.experimental import enable halving search cv from sklearn.model selection import HalvingRandomSearchCV from sklearn.ensemble import RandomForestClassifier param distributions = { 'n estimators': 50, 100, 200, 300 , 'max depth': 10, 20, 30, None , 'min samples split': 2, 5, 10 , 'min samples leaf': 1, 2, 4 , 'criterion': 'gini', 'entropy' } rf base = RandomForestClassifier random state=42, n jobs=-1 halving search = HalvingRandomSearchCV estimator=rf base, param distributions=param distributions, factor=3, resource='n samples', scoring='accuracy', random state=42, cv=3, verbose=1 halving search.fit X train, y train best model = halving search.best estimator print f"Optimal Parameters: {halving search.best params }" With our optimized ensemble model persisted, we can evaluate arbitrary, unseen patient records via direct inference: high risk patient = { 'CS SEXO': 1, 'NU IDADE N': 68, 'UTI': 1, 'SUPORT VEN': 1, 'CARDIOPATI': 1, 'DIABETES': 1, 'OBESIDADE': 1, 'RENAL': 0, 'ASMA': 0, 'IMUNODEPRE': 0 } input df = pd.DataFrame high risk patient mortality probability = best model.predict proba input df 0 1 print f"Calculated Risk Probability: {mortality probability 100:.2f}%" Using HalvingRandomSearchCV dramatically reduces iteration time on large datasets without sacrificing model performance. When combined with rigorous binary feature normalization and stratified sampling, developers can build robust risk-stratification pipelines ready for healthcare operational workflows.