Skip to main content
🚀 Projects

How to Build Your First Machine Learning Project from Scratch

A step-by-step tutorial for beginners on building a complete, end-to-end Machine Learning project — from choosing a dataset to deploying a simple model.

Harsha
Harsha
Written by
13 min read
Building your first machine learning project
Building your first machine learning project

Reading ML theory is useful. Building a real ML project is transformative.

This tutorial walks you through building a complete end-to-end ML project — a Loan Approval Predictor — from raw data to a deployed web application.

By the end, you’ll have a real project on GitHub that demonstrates the complete ML workflow.

What We’re Building

Project: Loan Approval Predictor Dataset: LendingClub (available free on Kaggle) Model: Random Forest Classifier UI: Streamlit web application

We’ll predict whether a loan applicant should be approved or denied based on their financial profile.

Step 1: Set Up Your Environment

# Create a virtual environment
python -m venv loan_predictor_env

# Activate it
# Windows:
loan_predictor_env\Scripts\activate
# Mac/Linux:
source loan_predictor_env/bin/activate

# Install dependencies
pip install pandas numpy scikit-learn matplotlib seaborn streamlit joblib

Create this project structure:

loan_predictor/
├── data/
│   └── loan_data.csv
├── notebooks/
│   └── exploration.ipynb
├── src/
│   ├── __init__.py
│   ├── preprocess.py
│   └── train.py
├── models/
│   └── (trained model will be saved here)
├── app.py          (Streamlit UI)
├── requirements.txt
└── README.md

Step 2: Load and Explore the Data

# src/explore.py
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

def load_and_explore(filepath: str):
    df = pd.read_csv(filepath)
    
    print("Dataset Shape:", df.shape)
    print("\nFirst 5 rows:")
    print(df.head())
    
    print("\nColumn Info:")
    print(df.info())
    
    print("\nMissing Values:")
    missing = df.isnull().sum()
    print(missing[missing > 0])
    
    print("\nTarget Distribution:")
    print(df['loan_status'].value_counts(normalize=True))
    
    return df

df = load_and_explore('data/loan_data.csv')

Key questions to answer during exploration:

  • What’s the class distribution? (Is it balanced?)
  • Which columns have missing values?
  • What are the numeric vs categorical columns?
  • Are there any obvious correlations?

Step 3: Data Preprocessing

# src/preprocess.py
import pandas as pd
import numpy as np
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.model_selection import train_test_split

def preprocess_data(df: pd.DataFrame):
    """Clean and prepare data for ML."""
    
    # Drop irrelevant columns
    columns_to_drop = ['id', 'member_id', 'url', 'desc']
    df = df.drop(columns=[c for c in columns_to_drop if c in df.columns])
    
    # Handle missing values
    # Numeric: fill with median
    numeric_cols = df.select_dtypes(include=['number']).columns
    for col in numeric_cols:
        df[col].fillna(df[col].median(), inplace=True)
    
    # Categorical: fill with mode
    categorical_cols = df.select_dtypes(include=['object']).columns
    for col in categorical_cols:
        df[col].fillna(df[col].mode()[0], inplace=True)
    
    # Encode target variable
    df['loan_approved'] = (df['loan_status'] == 'Fully Paid').astype(int)
    df = df.drop('loan_status', axis=1)
    
    # Encode categorical features
    label_encoders = {}
    for col in categorical_cols:
        if col != 'loan_status':
            le = LabelEncoder()
            df[col] = le.fit_transform(df[col].astype(str))
            label_encoders[col] = le
    
    # Separate features and target
    X = df.drop('loan_approved', axis=1)
    y = df['loan_approved']
    
    return X, y, label_encoders

X, y, encoders = preprocess_data(df)

Step 4: Feature Selection and Engineering

from sklearn.ensemble import RandomForestClassifier
import pandas as pd

def select_important_features(X, y, top_n=15):
    """Use Random Forest to identify the most important features."""
    
    rf = RandomForestClassifier(n_estimators=50, random_state=42, n_jobs=-1)
    rf.fit(X, y)
    
    importance = pd.Series(rf.feature_importances_, index=X.columns)
    importance = importance.sort_values(ascending=False)
    
    print("Top 15 Most Important Features:")
    print(importance.head(top_n))
    
    return importance.head(top_n).index.tolist()

top_features = select_important_features(X, y)
X_selected = X[top_features]

Step 5: Train and Evaluate the Model

# src/train.py
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.metrics import (
    accuracy_score, precision_score, recall_score, 
    f1_score, roc_auc_score, confusion_matrix, classification_report
)
import joblib
import numpy as np

def train_model(X, y):
    """Train and evaluate multiple models, save the best one."""
    
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=42, stratify=y
    )
    
    models = {
        'Random Forest': RandomForestClassifier(
            n_estimators=100, 
            max_depth=10,
            random_state=42,
            n_jobs=-1
        ),
        'Gradient Boosting': GradientBoostingClassifier(
            n_estimators=100,
            max_depth=5,
            random_state=42
        )
    }
    
    best_model = None
    best_score = 0
    
    for name, model in models.items():
        # Cross-validation
        cv_scores = cross_val_score(model, X_train, y_train, cv=5, scoring='roc_auc')
        print(f"\n{name}:")
        print(f"  CV ROC-AUC: {cv_scores.mean():.3f} (+/- {cv_scores.std():.3f})")
        
        # Train on full training set
        model.fit(X_train, y_train)
        y_pred = model.predict(X_test)
        y_prob = model.predict_proba(X_test)[:, 1]
        
        # Metrics
        print(f"  Test Accuracy:  {accuracy_score(y_test, y_pred):.3f}")
        print(f"  Test Precision: {precision_score(y_test, y_pred):.3f}")
        print(f"  Test Recall:    {recall_score(y_test, y_pred):.3f}")
        print(f"  Test F1:        {f1_score(y_test, y_pred):.3f}")
        print(f"  Test ROC-AUC:   {roc_auc_score(y_test, y_prob):.3f}")
        
        if roc_auc_score(y_test, y_prob) > best_score:
            best_score = roc_auc_score(y_test, y_prob)
            best_model = model
    
    # Save the best model
    joblib.dump(best_model, 'models/loan_predictor.pkl')
    print(f"\nBest model saved! ROC-AUC: {best_score:.3f}")
    
    return best_model, X_test, y_test

model, X_test, y_test = train_model(X_selected, y)

Step 6: Build the Web Interface with Streamlit

# app.py
import streamlit as st
import pandas as pd
import joblib
import numpy as np

# Page config
st.set_page_config(
    page_title="Loan Approval Predictor",
    page_icon="🏦",
    layout="wide"
)

@st.cache_resource
def load_model():
    return joblib.load('models/loan_predictor.pkl')

model = load_model()

# UI
st.title("🏦 Loan Approval Predictor")
st.markdown("Enter the applicant's financial details to predict loan approval probability.")

# Input form
col1, col2 = st.columns(2)

with col1:
    annual_income = st.number_input("Annual Income (₹)", min_value=0, value=600000, step=10000)
    loan_amount = st.number_input("Loan Amount (₹)", min_value=0, value=250000, step=5000)
    employment_years = st.slider("Years of Employment", 0, 40, 3)
    credit_score = st.slider("Credit Score (CIBIL)", 300, 900, 700)

with col2:
    debt_to_income = st.slider("Debt-to-Income Ratio (%)", 0.0, 100.0, 20.0)
    delinquencies = st.number_input("Past Delinquencies (last 2 years)", 0, 20, 0)
    home_ownership = st.selectbox("Home Ownership", ["Rent", "Own", "Mortgage"])
    purpose = st.selectbox("Loan Purpose", ["Debt Consolidation", "Education", "Home Improvement", "Business", "Other"])

# Prepare input for prediction
if st.button("Predict Loan Approval", type="primary", use_container_width=True):
    # Create feature vector (adapt to your actual features)
    input_data = pd.DataFrame({
        'annual_inc': [annual_income],
        'loan_amnt': [loan_amount],
        'emp_length': [employment_years],
        'fico_range_high': [credit_score],
        'dti': [debt_to_income],
        'delinq_2yrs': [delinquencies],
        'home_ownership': [0 if home_ownership == "Rent" else (1 if home_ownership == "Own" else 2)],
        'purpose': [["Debt Consolidation", "Education", "Home Improvement", "Business", "Other"].index(purpose)]
    })
    
    probability = model.predict_proba(input_data)[0][1]
    approved = probability > 0.5
    
    st.divider()
    
    if approved:
        st.success(f"✅ APPROVED — Approval Probability: {probability:.1%}")
    else:
        st.error(f"❌ DENIED — Approval Probability: {probability:.1%}")
    
    # Show confidence
    st.progress(probability)
    
    if probability > 0.8:
        st.info("Strong approval candidate.")
    elif probability > 0.6:
        st.info("Moderate approval probability. Some risk factors present.")
    else:
        st.warning("High risk profile. Consider improving credit score and reducing debt.")

Step 7: Create a Professional README

Your README is your first impression on GitHub. It must include:

# 🏦 Loan Approval Predictor

A Machine Learning web application that predicts loan approval 
probability based on an applicant's financial profile.

## 🎯 Problem Statement
Financial institutions manually process thousands of loan 
applications. This ML system automates initial screening 
with 87% accuracy, reducing processing time by 60%.

## 📊 Model Performance
| Metric | Score |
|--------|-------|
| Accuracy | 87.3% |
| Precision | 84.1% |
| Recall | 89.2% |
| ROC-AUC | 0.91 |

## 🛠️ Tech Stack
- Python 3.11
- scikit-learn (Random Forest, Gradient Boosting)
- Pandas, NumPy
- Streamlit
- Matplotlib, Seaborn

## 🚀 Run Locally
```bash
git clone https://github.com/yourusername/loan-predictor
cd loan-predictor
pip install -r requirements.txt
streamlit run app.py

📁 Dataset

LendingClub loan data from Kaggle — [link here]


## Step 8: Deploy (Free)

Deploy to **Streamlit Community Cloud** for free:

1. Push your code to GitHub
2. Go to share.streamlit.io
3. Connect your GitHub repository
4. Select `app.py` as the main file
5. Click Deploy

You get a public URL to share with recruiters.

## What This Project Demonstrates

On your resume, this project shows:
- ✅ Complete ML pipeline (data → model → deployment)
- ✅ Data preprocessing and cleaning skills
- ✅ Feature engineering and selection
- ✅ Model comparison and evaluation
- ✅ Production-ready code organisation
- ✅ UI development with Streamlit
- ✅ Deployment experience

**Resume line**: "Built an end-to-end loan approval prediction system (87% accuracy, ROC-AUC 0.91) using Random Forest. Deployed as a Streamlit web app — [link]"

That's a real project. Recruiters notice those.

Tags

machine learning projectbeginnerstutorialscikit-learndeploymentStreamlit
Harsha

Written byHarsha

AI/ML enthusiast and technology learner sharing practical guides, projects, tools and career resources for students and aspiring developers.

💬 Comments coming soon — connect via the social links above to share your thoughts.

Related Articles