Skip to content

Latest commit

Β 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🧠 Retail Customer Classification in Java

A multiclass machine-learning application that implements K-Nearest Neighbors (KNN) and a Decision Tree classifier from scratch in Java, without using external machine-learning libraries.

The project was originally developed as a university coursework project and later refined to improve its machine-learning methodology, reproducibility and portfolio quality.

The application includes CSV ingestion, preprocessing, deterministic train/test splitting, custom classification algorithms, multiclass evaluation metrics, confusion matrices and an interactive Java Swing interface.


πŸ“Œ Project Overview

The goal of the project is to predict the product category associated with a retail transaction using customer and transaction-related features.

The main features used by the models are:

  • Gender
  • Transaction net amount
  • Brand

The target variable is:

  • Product category

Two classification algorithms were implemented manually:

  • K-Nearest Neighbors (KNN)
  • Decision Tree using Gini Impurity

No external machine-learning framework such as Weka, scikit-learn or TensorFlow is used for the classifiers.


✨ Key Features

  • Custom KNN implementation
  • Custom Decision Tree implementation
  • Multiclass classification
  • CSV parsing and data cleaning
  • Deterministic train/test split
  • Train-only preprocessing
  • Min-Max normalization
  • Numerical and categorical feature handling
  • Gini impurity calculation
  • Recursive tree construction
  • KNN majority voting
  • Deterministic tie-breaking
  • Accuracy evaluation
  • Macro Precision
  • Macro Recall
  • Macro F1
  • Confusion Matrix
  • Training and inference time measurement
  • Interactive Java Swing GUI
  • Manual prediction interface
  • Model comparison visualization

πŸ—οΈ Machine Learning Pipeline

flowchart TD

    CSV["Retail Sales CSV"]

    CLEAN["Parsing & Cleaning"]

    SPLIT["Deterministic Train/Test Split<br/>Random Seed = 42"]

    FIT["Fit Preprocessor<br/>Training Data Only"]

    TRAIN["Transform Training Data"]
    TEST["Transform Test Data"]

    KNN["Custom KNN"]
    DT["Custom Decision Tree"]

    EVAL["Multiclass Evaluation"]

    GUI["Java Swing GUI"]

    CSV --> CLEAN
    CLEAN --> SPLIT

    SPLIT --> FIT

    FIT --> TRAIN
    FIT --> TEST

    TRAIN --> KNN
    TRAIN --> DT

    TEST --> KNN
    TEST --> DT

    KNN --> EVAL
    DT --> EVAL

    EVAL --> GUI
Loading

πŸ” Preventing Data Leakage

An important part of the preprocessing pipeline is that normalization parameters are learned only from the training dataset.

Incorrect approach:

Entire Dataset
      ↓
Normalization
      ↓
Train/Test Split

This allows information from the future test set to influence preprocessing.

The project instead uses:

Dataset
   ↓
Train/Test Split
   ↓
Training Data
   ↓
Learn Min / Max
   ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              β”‚              β”‚
β–Ό              β–Ό              β”‚
Train        Test             β”‚
β”‚              β”‚              β”‚
└──── Same training statistics

The test set therefore does not influence the parameters learned during preprocessing.


πŸ”’ Numerical Feature Processing

The transaction amount is a numerical feature.

Min-Max normalization is applied using values learned from the training set:

x_normalized = (x - train_min) / (train_max - train_min)

The same training-set minimum and maximum values are used for:

  • Training records
  • Test records
  • Manual predictions from the GUI

🏷️ Categorical Feature Handling

Brand is treated as a categorical feature.

Earlier versions of the coursework encoded brands using arbitrary numbers such as:

Brand A β†’ 600
Brand B β†’ 601
Brand C β†’ 602

This creates artificial mathematical relationships between brands.

For example:

distance(Brand A, Brand B) = 1
distance(Brand A, Brand C) = 2

There is no real semantic reason for such distances.

The refined implementation therefore preserves brand names as categorical values.


πŸ”΅ K-Nearest Neighbors

KNN was implemented manually in Java.

The algorithm:

  1. Calculates the distance between the input sample and each training record.
  2. Maintains the closest K neighbors using a PriorityQueue.
  3. Performs majority voting over their target categories.
  4. Uses distance-based deterministic tie-breaking when necessary.

Mixed Feature Distance

The KNN distance function combines numerical and categorical information.

Gender

Same gender      β†’ distance contribution = 0
Different gender β†’ distance contribution = 1

Transaction Amount

The normalized numerical difference is used:

amount_difference =
normalized_amount_1 - normalized_amount_2

Brand

Same brand      β†’ 0
Different brand β†’ 1

The combined distance is calculated using a Euclidean-style formulation.

distance =
sqrt(
    gender_differenceΒ²
    +
    amount_differenceΒ²
    +
    brand_mismatchΒ²
)

This prevents arbitrary numeric brand IDs from affecting neighborhood calculations.


🟠 Decision Tree

The Decision Tree classifier was also implemented manually.

The tree is constructed recursively using Gini Impurity to choose candidate splits.

For a dataset containing classes with probabilities p₁ ... pβ‚™:

Gini = 1 - Ξ£(pα΅’Β²)

The algorithm searches for splits that reduce the weighted impurity of the resulting child nodes.


Numerical Splits

For numerical features, candidate thresholds are generated between neighboring unique feature values.

Example:

transaction_amount <= threshold

Categorical Splits

Brands are evaluated using categorical equality splits:

brand == X

versus:

brand != X

This avoids treating brand names as ordered numerical values.


Recursive Tree Construction

The recursive training process stops when:

  • The maximum depth is reached
  • All samples belong to the same class
  • No useful split can be produced

Leaf nodes return the majority category of the remaining samples.


πŸ“Š Model Evaluation

The application evaluates multiclass performance using:

  • Accuracy
  • Macro Precision
  • Macro Recall
  • Macro F1
  • Confusion Matrix

Macro metrics are especially useful because the dataset contains classes with different frequencies.

Each class therefore contributes equally to the macro score regardless of the number of samples it contains.


πŸ† Example Results

Results below were obtained using the fixed deterministic split used by the application.

Model Configuration Accuracy Macro Precision Macro Recall Macro F1
KNN K = 3, Train = 90% 92.66% 94.38% 87.03% 89.82%
Decision Tree Depth = 10, Train = 80% 65.62% 55.67% 38.45% 41.42%

The KNN classifier performs substantially better on this dataset.

The Decision Tree's lower Macro Recall and Macro F1 also show why evaluating only accuracy can be misleading in multiclass and imbalanced datasets.

These values represent one deterministic train/test configuration and should not be interpreted as cross-validation results.


πŸ–₯️ Application Interface

The Java Swing interface allows users to:

  • Load a CSV dataset
  • Select KNN or Decision Tree
  • Configure K
  • Configure maximum tree depth
  • Change training percentage
  • Train and evaluate models
  • Compare previous model runs
  • View training time
  • View inference time
  • View Accuracy
  • View Macro Precision
  • View Macro Recall
  • View Macro F1
  • Display the confusion matrix
  • Perform manual predictions

πŸ“Έ Application Overview

Application Overview


🧩 Project Structure

Java-ML-Classification-From-Scratch/
β”‚
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ classifier/
β”‚   β”‚   β”œβ”€β”€ IClassifier.java
β”‚   β”‚   β”œβ”€β”€ KNNClassifier.java
β”‚   β”‚   └── KararAgaci.java
β”‚   β”‚
β”‚   β”œβ”€β”€ data/
β”‚   β”‚   └── DataYukle.java
β”‚   β”‚
β”‚   β”œβ”€β”€ evaluation/
β”‚   β”‚   └── Evaluator.java
β”‚   β”‚
β”‚   β”œβ”€β”€ gui/
β”‚   β”‚   └── MainGui.java
β”‚   β”‚
β”‚   β”œβ”€β”€ model/
β”‚   β”‚   └── UserRecord.java
β”‚   β”‚
β”‚   └── preprocess/
β”‚       └── PreProcessor.java
β”‚
β”œβ”€β”€ data/
β”‚   └── README.md
β”‚
β”œβ”€β”€ docs/
β”‚   └── images/
β”‚       └── application-overview.png
β”‚
β”œβ”€β”€ .gitignore
└── README.md

πŸ› οΈ Technology Stack

Category Technology
Programming Language Java
Machine Learning Custom implementation
GUI Java Swing
Data Processing Java Collections
Data Source CSV
Build javac
Version Control Git & GitHub

The project has no external machine-learning dependency.


πŸš€ Running the Project

Requirements

A Java Development Kit is required.

The project was originally developed using Java 8 and can be compiled with a compatible JDK.

Check:

java -version
javac -version

Dataset

The original coursework dataset is not redistributed in this repository.

Place your local copy in the repository root as:

MarketSalesKocaeli.csv

More information is available in:

data/README.md

Compile

Windows PowerShell

New-Item -ItemType Directory -Force out | Out-Null

javac -encoding UTF-8 -d out (Get-ChildItem -Recurse src -Filter *.java).FullName

Linux / macOS

mkdir -p out

javac -encoding UTF-8 -d out $(find src -name "*.java")

Run

java -cp out gui.MainGui

The application will attempt to use:

MarketSalesKocaeli.csv

as its default local dataset.

A different compatible CSV file can also be selected through the GUI.


πŸ§ͺ Methodology Improvements

The original coursework implementation was later reviewed and improved.

Important corrections include:

Before

Full-dataset normalization
Arbitrary numerical brand encoding
Random train/test split on every run
Accuracy-only evaluation

Current Version

Training-only preprocessing
Categorical brand representation
Deterministic split using seed 42
Non-mutating preprocessing
Mixed numerical/categorical KNN distance
Categorical Decision Tree splits
Accuracy + Precision + Recall + Macro F1
Confusion Matrix

These changes improve methodological correctness and reproducibility without replacing the original manually implemented algorithms.


⚠️ Limitations

This project is primarily intended to demonstrate machine-learning fundamentals and algorithm implementation.

Current limitations include:

  • Evaluation uses a fixed train/test split rather than cross-validation
  • No automatic hyperparameter optimization
  • The dataset contains class imbalance
  • Decision Tree categorical splits use one-category-vs-rest comparisons
  • KNN uses an intentionally simple mixed-feature distance function
  • The original course dataset has no known public redistribution license
  • The system is designed as a desktop academic application rather than a production ML service

These limitations provide clear opportunities for future experimentation.


πŸ—ΊοΈ Possible Future Improvements

  • K-fold cross-validation
  • Stratified train/test splitting
  • Per-class precision, recall and F1 reporting
  • Hyperparameter search
  • Feature weighting for KNN
  • Improved categorical Decision Tree splitting
  • Unit tests
  • Maven or Gradle build configuration
  • Exportable evaluation reports

πŸŽ“ Academic Context

This project originated as a university programming laboratory / machine-learning coursework project.

The objective was to understand classification algorithms by implementing their internal logic manually rather than relying on pre-built machine-learning libraries.

The repository was later cleaned and refined for portfolio use while preserving that original learning objective.


πŸ‘€ Author

Ahmet Avdatek

Computer Engineering student focused on Data Engineering, machine learning fundamentals and data-intensive systems.

About

KNN and Decision Tree implemented from scratch in Java with train-only preprocessing, multiclass evaluation and a Swing GUI.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages