Digitalise Agency

earnings-regression

Earnings Regression

Does more schooling, or more years of work, mean a higher hourly wage? This fits a trend line through a public survey of American young people: move two sliders, schooling and experience, and it predicts a wage. The answer: those two facts barely predict anything. Tested on people it had never seen, it scores -0.008, slightly worse than guessing the average wage for everyone, reported rather than hidden.

Solo

Solo work by our founder, Salman Adnan.

The Fitting Surface: an animation of what fitting a trend line means. Each point is a person, the sheet is the model's guess at their wage, and it ripples until it sits as close to all of them as it can. Live and interactive: drag it to orbit, scroll or pinch to zoom. Open full screen
Distribution of actual vs predicted earnings residuals from the real regression model.
Real model output on the NLSY97 survey data.
2,000NLSY97 survey rows
492usable rows after cleaning
-0.008held-out test R-squared, real result

Overview

A multivariable linear regression that predicts hourly earnings from years of schooling and years of work experience, using a 2,000-row subset of the NLSY97 (National Longitudinal Survey of Youth 1997-2011), served through an interactive Plotly/Flask dashboard as well as a plain headless script.

Key features

  • Loads and cleans the NLSY97 subset (drops rows with missing values and duplicates), then fits a simple regression (earnings on schooling alone) and a multivariable regression (earnings on schooling and experience), reporting R-squared on both a training split and a held-out 20% test split.
  • A live prediction panel: two sliders (schooling, experience) that call a /predict API endpoint on every move and display the real model's output, not a hardcoded formula.
  • A Plotly scatter of actual vs. predicted earnings on the held-out test split, with a y = x reference line for perfect prediction.
  • A 3D Plotly surface of predicted earnings across the entire schooling/experience plane, with the real training rows plotted on top of it as points.
  • A residuals plot (predicted minus actual) against predicted earnings, plus a headless mode (main.py) that still prints the same exploration output and writes the same two static PNGs it always did.

Verification

The prediction endpoint was hit directly and returned a real model output: {"experience":5.0,"predicted_earnings":20.29,"schooling":16.0} for 16 years of schooling and 5 years of experience. The multivariable model's held-out test R-squared came out at -0.008, meaning on this split it performs marginally worse than predicting the mean training earnings for everyone. That's reported as-is rather than hidden: with only two features and 492 usable rows after dropping missing values, the model isn't capturing much of what actually drives earnings.

Tech stack

  • Python
  • scikit-learn
  • pandas
  • Plotly
  • Flask
  • matplotlib / seaborn

Book a call

Let's talk about what you're building.

Pick a slot below.