# The three model families benchmarked across all three tasks.
models = {
"logistic": LogisticRegression(...),
"random_forest": RandomForestClassifier(...),
"xgboost": XGBClassifier(...),
}Predictive Modeling of U.S. Oral Health Outcomes
Logistic regression, random forests, and XGBoost on NHANES 2017–2018.
Summary. With a team of three, I led the shallow-learning analysis on NHANES 2017–2018 (n=5,265 adults), benchmarking logistic regression, random forests, and XGBoost across two binary classification tasks and one regression task. Best models hit a 5-fold CV ROC-AUC of 0.849 (self-rated oral health) and 0.844 (clinician-recommended care). A two-stage regression cut DMFT mean absolute error from 6.98 to 4.67 teeth (33%) using only socioeconomic predictors.
DSAN 5300, Statistical Learning, Spring 2026. I owned the data preprocessing pipeline and co-authored the manuscript.
The setup
Oral disease affects an estimated 3.7 billion people globally, and untreated caries in permanent teeth is the single most common health condition worldwide. It’s also highly preventable, which makes the persistence of disease less a biomedical question than a question of who can access dental care. The socioeconomic gradient in U.S. oral health is one of the most established findings in public health, adults below the poverty line have roughly twice the untreated-decay rate of adults at five times the poverty threshold, and that gap has been stable for two decades.
Most prior work models this with logistic regression on a handful of pre-selected covariates, optimizing for interpretable coefficients rather than out-of-sample performance. We wanted to ask a different question: how far can you get predicting oral-health outcomes from upstream socioeconomic and access-to-care variables alone, with no clinical exam data? That framing has a practical payoff. If a short list of routinely collected survey items can flag adults at risk of unmet dental need, that’s a screening tool usable in primary care settings where no dentist is present. We tested it across three tasks: predicting self-rated fair/poor oral health, predicting whether a clinical examiner recommended care, and predicting the continuous DMFT (Decayed, Missing, Filled Teeth) score.
Data and preprocessing
I owned the preprocessing pipeline, which was most of the real work. We merged four NHANES 2017–2018 SAS transport files on the participant sequence number: demographics (DEMO_J), the dentition exam (OHXDEN_J), the oral-health questionnaire (OHQ_J), and the examiner’s care recommendation (OHXREF_J). Restricting to adults 20+ who completed both the interview and the mobile examination center exam gave a working sample of 5,265.
Three preprocessing decisions mattered more than the rest. First, NHANES stores refusals and “don’t know” as numeric sentinel values (7/77, 9/99), which a model will happily treat as real magnitudes, so those were converted to NaN across eleven questionnaire variables. Second, the 28 tooth-level caries codes and 32 tooth-status codes were collapsed into interpretable summary features: counts of decayed, filled, and missing-due-to-caries teeth, a DMFT score computed by the Klein-Palmer method, a treatment ratio (filled-sound teeth over teeth that ever decayed) as a proxy for restorative-care access, and a binary edentulous indicator. Third, the eleven care-barrier items are only populated for respondents who first reported unmet need, so missingness there reflects the survey’s skip pattern rather than non-response, and was interpreted as “barrier not reported” rather than imputed.
One leakage check worth naming: the Task 1 target is derived directly from the self-rated oral health item, which correlates with it at r = 0.82. That item is excluded from the Task 1 feature set for exactly that reason.
Models
For the two classification tasks we ran a randomized hyperparameter search over tree count, max depth, learning rate, subsample and column-subsample ratios, minimum child weight, and gamma, tuned on ROC-AUC under 5-fold stratified cross-validation. Preprocessing (imputation, scaling) was fit inside each fold on the training portion only, so nothing leaked from validation into training. Class imbalance was handled with balanced class weights on the linear and forest models and a scaled positive-class weight on XGBoost.
The DMFT regression needed a structural fix rather than a tuning fix. About 11.5% of adults in the sample are edentulous, and 63% of those have a DMFT of exactly 28, producing a large point mass at the top of the scale. Having no teeth is a categorically different state from having severe decay, not just a more extreme version of it. So Task 3 uses a two-stage model inside each CV fold: an XGBoost classifier predicts edentulous status, those participants are assigned DMFT = 28, and a separate XGBoost regressor trained only on dentate adults predicts the rest.
Results
Across all three tasks, gradient-boosted trees came out on top, though not by much.
| Task | Best model | Headline metric |
|---|---|---|
| Poor self-rated oral health | XGBoost (tuned) | ROC-AUC 0.849 (vs 0.841 logistic) |
| Clinician-recommended care | XGBoost (tuned) | ROC-AUC 0.844 (vs 0.831 logistic) |
| DMFT score (upstream features only) | XGBoost (two-stage) | MAE 4.67 teeth (vs 6.98 naive baseline) |
The DMFT result is the one I’d point to. Predicting the mean for everyone gives an MAE of 6.98 teeth; using only socioeconomic and access-to-care predictors, with no clinical exam data at all, cuts that to 4.67, a 33% reduction. The single-stage model scored a slightly higher R² (0.469 vs 0.431) because R² rewards capturing the full distribution including the edentulous cluster, but MAE, which is interpretable in units of teeth and penalizes that cluster more evenly, favors the two-stage approach.
What surprised me
Most of the signal turned out to be linear. With ~30 socioeconomic, access, and barrier features and no single dominant predictor, I expected boosting to pull meaningfully ahead by finding interactions. It didn’t, regularized logistic regression landed within about 0.01 AUC of tuned XGBoost on both classification tasks. The strongest predictors (income-to-poverty ratio, age, education, time since last dental visit) appear to operate additively on the log-odds scale. There’s some non-linear structure left over, but far less than the feature count would suggest.
The edentulous subgroup broke my intuition about the care-recommendation target. Adults with no natural teeth were older, poorer, and less educated than the rest of the sample, yet showed a lower rate of examiner-recommended care. That isn’t better oral health, it’s that once there are no teeth left, there are fewer tooth-level recommendations an examiner can make. A model trained naively on the full sample will understate care needs for one of the most vulnerable groups in the data, which is a good example of a metric looking fine while the model quietly fails the people who matter most.
Caveats
A model that predicts oral-health outcomes from socioeconomic predictors is also, implicitly, a model of structural inequity. The accuracy is real, and so is the responsibility to think hard about how a result like this gets used.
Three methodological limits worth stating plainly. The data are cross-sectional, so everything here is predictive rather than causal, we make no claim that income causes poor oral health. We evaluated with standard cross-validation and did not fully incorporate the NHANES survey weights and complex sampling design, which limits how far these numbers generalize to national estimates. And the same core predictors topping the importance rankings across all three tasks is a finding, but it also means the three models are less independent than their separate framings imply.