Overview
Baby Names Explorer is an interactive data application for exploring 145 years of US baby name trends from the Social Security Administration. You can browse the most popular names for any year since 1880, pull up the full history of any single name with a statistical forecast of where it's heading, and ask questions about the whole dataset in plain English.
The project grew from a simple question: is a name getting more or less popular, and will that trend continue? The SSA publishes name data going back to 1880, but raw data files are not interactive. Building this meant designing a data pipeline, working out a forecasting approach that holds up under validation, and wrapping it in a UI that makes the analysis accessible.
It started as a single-file Streamlit app. It has since been rebuilt as a Next.js frontend over a FastAPI backend, with the querying, forecasting, and chatbot logic split into services that can be tested independently of the UI.
Data Pipeline
The SSA doesn't offer a direct API download — the data comes as a ZIP archive from a page that blocks automated requests. The pipeline handles this with Selenium to automate the download, then processes all ~145 annual text files into a single normalized dataset.
For each name-sex-year combination, the pipeline computes:
total_count— raw number of births with that namepopularity_percent— count as a fraction of all births that year and sex, correcting for population growthpopularity_rank— ranking within year and sex (1 = most popular)
Relative metrics matter more than raw counts here. A mid-century name given to 30,000 babies was a genuine cultural phenomenon; the same raw count today, spread across a far larger and far more varied pool of births, is not. Share of births says which of those two happened. The pipeline also back-fills zero-count rows so every name has a continuous yearly series rather than gaps, which matters downstream — a time-series model can't be fit to a series with holes in it. The result is stored in a SQLite database the backend queries read-only.
Forecasting
The forecasting task is time-series prediction: given a name's popularity trajectory, project where it goes over the next five years. The approach is ARIMA, and most of the work is in choosing the model rather than running it.
For each name, the backend:
- Log-transforms series with high relative variance, since name popularity tends to grow and decay multiplicatively rather than by fixed increments.
- Determines the differencing order by running ADF and KPSS stationarity tests and differencing until both agree the series is stationary.
- Grid-searches ARIMA orders around that differencing order, selecting by AICc — the small-sample-corrected criterion, which matters because some names only have a few decades of usable history.
- Validates on a five-year holdout: refit on everything but the last five years, forecast forward, and report MAE, RMSE, and MAPE against what actually happened.
- Runs residual diagnostics — Ljung-Box for autocorrelation, Jarque-Bera for normality, ARCH for heteroscedasticity — and surfaces whether the fit actually satisfies the model's assumptions.
Forecasts are returned with 80% and 95% confidence intervals rather than a single line. A single point forecast implies a precision this data doesn't support, and the interval width is the honest way to say so. Fitting is CPU-bound, so results are cached per name and sex.
Natural-Language Querying
The chat feature translates questions into SQL rather than trying to answer them from a model's memory. Two LLM calls per question, through Groq: one generates a SELECT against the names schema, and one phrases the returned rows as an answer.
The generated SQL is the untrusted part, so it's treated that way. Before anything runs, the query has to start with SELECT, is rejected outright if it contains any of a list of mutating or introspection keywords, and has a LIMIT injected or clamped down to 1,000 rows. It then executes on a read-only connection. The SQL is displayed with every answer — partly so the reasoning is auditable, and partly because a query that returns something surprising is usually a more interesting result than the summary of it.
Skills Demonstrated
This project covers the full data lifecycle: raw data acquisition against a site that resists it, data engineering across 145 files, statistical time-series modeling with real model selection and validation, and an LLM feature built with the assumption that the model's output is hostile input. The forecasting choice reflects how I approach modeling — a well-specified ARIMA with diagnostics I can interpret and confidence intervals I can defend beats a black-box regressor for a problem that is genuinely a univariate time series.
