Predicting a student's expected placement salary (LPA) using Linear, Ridge, and Lasso Regression, with full EDA, feature engineering, hyperparameter tuning, regularization analysis, and a deployed Streamlit prediction app.
π Live Demo: Try it here | π Notebook: student_placement_analysis.ipynb
This project builds an end-to-end regression pipeline that predicts the salary package (LPA) a student is likely to receive at placement, based on academic performance, technical skills, internships/projects, and interview readiness. It compares three regression approaches β Linear, Ridge (L2), and Lasso (L1) β and automatically selects the best-performing model, which is then served through an interactive Streamlit app.
Placement cells and students alike want a data-driven way to estimate expected salary ranges given a student's current profile β both to set realistic expectations and to identify which factors (CGPA, DSA practice, internships, backlogs, etc.) actually move the needle. This project frames that as a supervised regression problem.
- Build a clean, reproducible ML pipeline: preprocessing β feature engineering β modeling β tuning β evaluation.
- Compare Linear Regression against L2 (Ridge) and L1 (Lasso) regularization, and explain why one wins.
- Diagnose multicollinearity (correlation + VIF) and show how regularization handles it better than plain OLS.
- Demonstrate Lasso's automatic feature selection.
- Ship a working, deployable prediction interface (Streamlit), not just a notebook.
data/student_placement_salary.csv β 1,500 records, synthetically generated (see src/generate_data.py for full assumptions) since no public dataset matches this exact, interview-relevant feature set. Salary is generated as an explicit, documented linear combination of the features below plus Gaussian noise and a backlog penalty, so the ground-truth relationship is realistic and close to linear β the right regime to test Linear/Ridge/Lasso fairly, rather than a strawman random dataset.
Students who were not placed (~12%, salary = 0 by construction) are excluded before regression training, since 0 represents "not placed," not "low salary" β mixing the two would corrupt the target.
| Category | Features |
|---|---|
| Academics | CGPA, 10th %, 12th % |
| Technical Skills | Coding Score, DSA/LeetCode Score, Aptitude Score, Technical Interview Score |
| Soft Skills | Communication Score |
| Experience | Internships, Projects, Certifications, Hackathons, Work Experience (months) |
| Conduct | Backlogs, Attendance % |
| Preparation | Placement Training Hours |
| Engineered | Academic_Score, Skill_Score, Experience_Score, Overall_Placement_Score |
| Target | Salary_LPA |
Python 3 Β· pandas Β· NumPy Β· scikit-learn Β· statsmodels (VIF) Β· Matplotlib Β· Seaborn Β· Streamlit Β· joblib
- Linear Regression β baseline OLS.
- Ridge Regression β L2 regularization, alpha tuned via
GridSearchCVover[0.01, 0.1, 1, 10, 100, 1000], 5-fold CV. - Lasso Regression β L1 regularization, alpha tuned via
GridSearchCVover[0.001, 0.01, 0.05, 0.1, 0.5, 1, 5, 10], 5-fold CV.
Raw CSV
β
βΌ
Load & validate (missing values, duplicates, dtypes)
β
βΌ
Filter to Placed students only
β
βΌ
Feature Engineering (Academic_Score, Skill_Score, Experience_Score, Overall_Placement_Score)
β
βΌ
Train/Test Split (80/20, random_state=42)
β
βΌ
StandardScaler β fit on TRAIN ONLY (no leakage)
β
βΌ
Train Linear / Ridge (GridSearchCV) / Lasso (GridSearchCV)
β
βΌ
Evaluate: MAE, MSE, RMSE, RΒ² + 5-Fold Cross-Validation
β
βΌ
Select best model β Residual Analysis β Save pipeline (joblib)
β
βΌ
Streamlit App (app.py) loads pipeline β live predictions
Key plots (see notebooks/student_placement_analysis.ipynb and reports/figures/):
- Salary distribution β right-skewed, most students in the 6β16 LPA range.
- CGPA vs Salary β clear positive linear trend; CGPA is the strongest single driver.
- Internships / Projects vs Salary β positive relationships, internships stronger than projects.
- Coding Score vs Salary β strong positive correlation, second only to CGPA.
- Correlation heatmap β CGPA, Coding_Score, DSA_Score, Technical_Interview_Score are mutually correlated and correlated with salary β motivates the multicollinearity check below.
Computed both a correlation matrix and VIF (Variance Inflation Factor). Several engineered composite features (e.g. Overall_Placement_Score, which is built from Academic_Score and Skill_Score) show very high VIF, since they are linear combinations of other features already in the model. This is an intentional stress test: it demonstrates the exact scenario where Ridge and Lasso are expected to outperform (or at least out-stabilize) plain OLS, since OLS coefficients become unstable/unreliable under high multicollinearity while regularized regression handles it gracefully.
Test-set results from the latest training run (models/summary.json):
| Model | MAE | MSE | RMSE | RΒ² | CV RΒ² (5-fold) |
|---|---|---|---|---|---|
| Linear Regression | 0.8114 | 1.0641 | 1.0315 | 0.5812 | 0.4927 (Β± 0.0252) |
| Ridge Regression (Ξ±=10) | 0.8119 | 1.0646 | 1.0318 | 0.5810 | 0.4929 (Β± 0.0251) |
| Lasso Regression (Ξ±=0.01) | 0.8125 | 1.0670 | 1.0330 | 0.5801 | 0.4943 (Β± 0.0242) |
Selected model: Linear Regression (highest test RΒ², confirmed by cross-validation showing no meaningful overfitting β train RΒ² β 0.51, test RΒ² β 0.58, CV RΒ² β 0.49 are all close together).
Why this result makes sense: the data was generated from a near-linear ground truth with moderate, realistic noise (see src/generate_data.py). With that little intrinsic non-linearity/overfitting risk, heavy regularization has little accuracy to gain β Ridge and Lasso land within ~0.1% RΒ² of plain Linear Regression. Their real value here isn't raw accuracy; it's coefficient stability under multicollinearity (Ridge) and automatic feature selection (Lasso) β see below. On noisier or more collinear real-world data, Ridge/Lasso would be expected to pull further ahead of plain Linear Regression.
- Ridge (L2): shrinks all coefficients smoothly towards zero but keeps every feature in the model.
- Lasso (L1): can shrink coefficients exactly to zero β i.e. performs automatic feature selection.
In this project, Lasso zeroed out 5 features entirely: Projects, Aptitude_Score, Technical_Interview_Score, Academic_Score, Skill_Score. Note that three of these are the engineered composite scores (or features they heavily overlap with) β Lasso correctly identified that once CGPA, Coding_Score and DSA_Score are already in the model, the composite scores built from them add redundant information rather than new signal.
Coefficient comparison chart: reports/figures/coefficient_comparison.png.
For the best model (Linear Regression):
- Residual mean: -0.056 (close to 0, indicating no strong systematic bias)
- Residual std: 1.030
- Actual vs Predicted plot shows points clustered around the diagonal with no strong curvature.
- Residual plot shows no obvious funnel/heteroscedasticity pattern.
- Residual distribution is approximately normal/unimodal.
Together these diagnostics suggest a reasonable, well-behaved linear fit rather than a systematically biased or misspecified model. See reports/figures/actual_vs_predicted.png, residual_plot.png, residual_distribution.png.
- Best model achieves RΒ² = 0.58 and RMSE β 1.03 LPA on unseen test data β i.e. predictions are typically within about Β±1 LPA of the true package, which is a realistic, non-inflated result for noisy, real-world-style placement data (not an artificially perfect RΒ² that would suggest data leakage or an unrealistic synthetic dataset).
- The full pipeline (scaler + model + feature list) is bundled in
models/best_model.pklviajoblib, so training-time preprocessing is guaranteed to match inference-time preprocessing.
app.py provides:
- Input section β sliders/number inputs for all 16 raw student features, grouped into Academics / Skills / Experience & Activities.
- Prediction β displays
Predicted Salary: βΉX LPAand theRecommended Model(the model selected during training). - Model Insights β best model name, RΒ², RMSE, MAE, full model comparison table, and standardized feature coefficients, plus a note on which features Lasso eliminated.
git clone <your-repo-url>
cd student-placement-salary-prediction
pip install -r requirements.txt# 1. Generate the synthetic dataset
python src/generate_data.py
# 2. (Optional) Generate EDA / diagnostic plots
python src/make_plots.py
# 3. Train all three models, tune, evaluate, and save the best pipeline
python src/train.py
# 4. (Optional) Re-evaluate the saved model
python src/evaluate.py
# 5. (Optional) Run a CLI prediction demo
python src/predict.py
# 6. Launch the Streamlit app
streamlit run app.pyThe Jupyter notebook (notebooks/student_placement_analysis.ipynb) contains the full narrated analysis with all plots embedded β open it with jupyter notebook or view it directly on GitHub.
student-placement-salary-prediction/
β
βββ data/
β βββ student_placement_salary.csv
β
βββ notebooks/
β βββ student_placement_analysis.ipynb
β
βββ reports/
β βββ figures/ # EDA + diagnostic plots (PNG)
β
βββ src/
β βββ generate_data.py # Synthetic dataset generation
β βββ data_preprocessing.py # Load, clean, feature-engineer, split, scale
β βββ make_plots.py # EDA + diagnostic plot generation
β βββ train.py # Train, tune (GridSearchCV), evaluate, save
β βββ evaluate.py # Reload saved model, print full report
β βββ predict.py # Single-student prediction function
β βββ build_notebook.py # Programmatically builds the analysis notebook
β
βββ models/
β βββ best_model.pkl # Saved pipeline: scaler + best model + metadata
β βββ model_comparison.csv
β βββ coefficients.csv
β βββ vif.csv
β βββ summary.json
β
βββ app.py # Streamlit application
βββ requirements.txt
βββ README.md
βββ .gitignore
- Why Linear Regression? It's the natural baseline for a continuous target with roughly linear relationships to the inputs β interpretable coefficients, fast to train, and a sanity check for whether more complex models are even needed.
- What problem does Ridge solve? It reduces coefficient variance/instability caused by multicollinearity by adding an L2 penalty (sum of squared coefficients) to the loss, shrinking coefficients smoothly.
- What problem does Lasso solve? Same instability problem, but via an L1 penalty (sum of absolute coefficients) that can drive some coefficients to exactly zero β combining regularization with feature selection.
- L1 vs L2: L1 (Lasso) uses absolute value of coefficients as the penalty and produces sparse solutions (some coefficients = 0). L2 (Ridge) uses squared coefficients and shrinks everything smoothly but rarely to exactly zero. Geometrically, L1's diamond-shaped constraint region has corners on the axes (where a coefficient is 0), which is why it induces sparsity, while L2's circular region doesn't.
- Why feature scaling is required: Ridge/Lasso penalize coefficient magnitude directly, so unscaled features with larger natural ranges would be penalized unfairly relative to their true importance.
StandardScalerputs all features on a comparable footing (mean 0, std 1). - What is alpha? The regularization strength hyperparameter. Alpha = 0 reduces Ridge/Lasso to plain OLS; larger alpha shrinks coefficients more aggressively (higher bias, lower variance).
- How GridSearchCV selects alpha: It exhaustively trains/evaluates the model for every alpha in the given grid using k-fold cross-validation, then picks the alpha with the best average validation score (RΒ² here) β avoiding overfitting to a single train/test split.
- Why Lasso performs feature selection: Its L1 penalty's constraint region has sharp corners aligned with the coordinate axes, so the optimal solution frequently lands exactly on an axis (coefficient = 0) rather than just near it, unlike Ridge's smooth circular constraint.
- What is multicollinearity? When two or more input features are highly correlated with each other, making it hard for OLS to isolate each feature's individual effect β coefficients become unstable and hard to interpret. Detected here via correlation matrix and VIF.
- Why RΒ² is used: It measures the proportion of variance in the target explained by the model (1.0 = perfect, 0 = no better than predicting the mean), giving an intuitive, scale-independent measure of fit quality.
- MAE vs MSE vs RMSE: MAE (mean absolute error) is the average absolute prediction error, robust to outliers. MSE (mean squared error) squares errors before averaging, penalizing large errors more heavily. RMSE is the square root of MSE, bringing the error back to the target's original units (LPA here) for interpretability.
- How cross-validation works: The training data is split into k folds; the model trains on kβ1 folds and validates on the remaining fold, k times, rotating which fold is held out. Averaging the k scores gives a more robust performance estimate than a single train/test split.
- How to detect overfitting: Compare train, test, and cross-validation performance. A large gap (high train score, much lower test/CV score) signals overfitting. Here, train RΒ² (0.51), test RΒ² (0.58) and CV RΒ² (0.49) are all close, indicating no significant overfitting.
- Why the final model was selected: Linear Regression had the highest test RΒ² and its cross-validation score closely matched Ridge and Lasso, confirming the near-linear ground truth doesn't require regularization for raw accuracy β though Ridge/Lasso remain valuable for coefficient stability and feature selection, and would be preferred in noisier, more collinear real-world settings.
Dataset is synthetic and generated for educational/portfolio purposes; predictions are estimates, not guarantees of actual placement offers.