A logistic regression model that predicts whether a job candidate will be Hired based on their experience, project history, certifications, education, and the role they applied for.
This project builds an end-to-end machine learning pipeline — from raw candidate data to a trained, evaluated, and stress-tested classifier — to predict hiring outcomes. The goal wasn't just to fit a model, but to demonstrate a full, honest ML workflow: EDA, cleaning, encoding, class-imbalance handling, evaluation, and validation on unseen data.
⚠️ Note on the data:cv_dataset.csv,cv_dataset_test1.csv, andcv_dataset_test2.csvare synthetically generated datasets, built to mimic realistic hiring patterns (moderate, non-deterministic correlation between experience/projects/certifications and hiring outcome). It does not represent real candidates, companies, or hiring decisions.
| Column | Description |
|---|---|
Name, Email, Phone |
Candidate identifiers (dropped before modeling) |
Years_Experience |
Years of professional experience (0–15) |
Education |
bachelor / master / phd |
Projects_Count |
Number of completed projects (0–7) |
Certifications_Count |
Number of certifications held (0–4) |
Role_Applied |
One of 9 data-related job titles |
Hired |
Target — 1 = Hired, 0 = Not Hired |
- 1,000 rows, no missing values, no duplicates
- Target balance: ~61% Hired / 39% Not Hired
- EDA — distribution checks, correlation heatmap, IQR-based outlier screening (none found), hiring breakdown by role
- Cleaning — dropped PII columns (
Name,Email,Phone), one-hot encodedEducationandRole_Applied - Splitting — 80/20 train/test split (
random_state=42) - Scaling —
StandardScalerapplied to the three continuous numerical features - Modeling —
LogisticRegression(class_weight='balanced', max_iter=1000)to correct for class imbalance - Evaluation — confusion matrix, classification report, and 5-fold cross-validation
The model was evaluated on three independent test sets — the original held-out split, plus two freshly generated, never-before-seen synthetic samples — to check that performance holds up beyond a single lucky split.
| Class | Precision | Recall | F1-score | Support |
|---|---|---|---|---|
| 0 (Not Hired) | 0.63 | 0.62 | 0.62 | 81 |
| 1 (Hired) | 0.74 | 0.76 | 0.75 | 119 |
Accuracy: 0.70 | Macro F1: 0.69 | 5-fold CV: [0.68, 0.645, 0.72, 0.66, 0.715] → mean 0.684
| Class | Precision | Recall | F1-score | Support |
|---|---|---|---|---|
| 0 (Not Hired) | 0.60 | 0.69 | 0.64 | 26 |
| 1 (Hired) | 0.73 | 0.65 | 0.69 | 34 |
Accuracy: 0.67 | Macro F1: 0.67 | 5-fold CV: [0.683, 0.70, 0.60, 0.70, 0.75] → mean 0.687
| Class | Precision | Recall | F1-score | Support |
|---|---|---|---|---|
| 0 (Not Hired) | 0.41 | 0.60 | 0.49 | 15 |
| 1 (Hired) | 0.84 | 0.71 | 0.77 | 45 |
Accuracy: 0.68 | Macro F1: 0.63 | 5-fold CV: [0.667, 0.65, 0.60, 0.65, 0.75] → mean 0.663
| Metric | Test 1 | Test 2 | Test 3 | Average |
|---|---|---|---|---|
| Accuracy | 0.70 | 0.67 | 0.68 | 0.683 |
The tight spread (67–70%) across three independently sampled test sets is the key takeaway: the model's performance is stable, not a fluke of one train/test split. Test Set 3's lower class-0 precision (small support of only 15) is a reminder that metrics on small samples are noisier — worth flagging, not a red flag on its own.
Python · pandas · numpy · scikit-learn · matplotlib · seaborn
pip install pandas numpy scikit-learn matplotlib seaborn
jupyter notebook cv_model_dummy.ipynb- Correcting for class imbalance with
class_weight='balanced'meaningfully improved recall on the minority class (Not Hired) without an unreasonable accuracy trade-off. - Validating on multiple freshly generated test sets — not just one split — gives much more confidence that ~68–70% accuracy reflects genuine generalization rather than overfitting to a single sample.
- The moderate accuracy ceiling (~70%) is expected and intentional: the underlying data has realistic, non-deterministic correlation between features and the hiring outcome, similar to how messy real-world hiring signals actually are.
- Hyperparameter tuning via
GridSearchCV - Comparison against tree-based models (Random Forest, Gradient Boosting)
- Threshold tuning on
predict_probafor use-case-specific precision/recall trade-offs