Built for a Data Mining course, then cleaned up and documented as a standalone project.
Seven unsupervised clustering algorithms run on the same dataset and scored with the same six metrics, to see whether they agree — and what to do when they don't.
Dataset: Titanic passenger data (data/Titanic_train.csv). The known Survived label is held out of the clustering and used only afterwards, as ground truth for the external metrics.
| Hierarchical — Ward linkage | scipy.cluster.hierarchy |
| Hierarchical — Complete linkage | scipy.cluster.hierarchy |
| Hierarchical — Average linkage | scipy.cluster.hierarchy |
| K-Means | sklearn.cluster |
| EM / Gaussian Mixture | sklearn.mixture |
| DBSCAN | sklearn.cluster |
| BIRCH | sklearn.cluster |
Features are standardised with StandardScaler before clustering; PCA is used for the 2-D scatter plots only, not for the clustering itself.
| Method | Clusters | Noise | ARI | NMI | Homogeneity | Completeness | V-measure | Silhouette |
|---|---|---|---|---|---|---|---|---|
| Hierarchical — Ward | 2 | 0 | 0.0012 | 0.0000 | 0.0000 | 0.0001 | 0.0000 | 0.3932 |
| Hierarchical — Complete | 2 | 0 | −0.0216 | 0.0238 | 0.0156 | 0.0509 | 0.0238 | 0.3910 |
| Hierarchical — Average | 2 | 0 | −0.0067 | 0.0076 | 0.0042 | 0.0417 | 0.0076 | 0.4597 |
| K-Means | 2 | 0 | 0.0005 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.3974 |
| EM / Gaussian Mixture | 2 | 0 | −0.0146 | 0.0049 | 0.0041 | 0.0061 | 0.0049 | 0.3694 |
| DBSCAN | 7 | 34 | 0.1906 | 0.1517 | 0.2481 | 0.1093 | 0.1517 | 0.3100 |
| BIRCH | 2 | 0 | 0.0616 | 0.0466 | 0.0475 | 0.0457 | 0.0466 | 0.1677 |
Full table: results/clustering_results.csv. Plots: figures/.
The internal and external metrics point at different winners. Hierarchical–Average has the best silhouette score (0.46) — the most geometrically clean separation — and an Adjusted Rand Index of essentially zero. Its clusters are tidy and tell you nothing about who survived. DBSCAN is the reverse: the worst-shaped clusters of the group (silhouette 0.31) but by far the best agreement with the ground truth (ARI 0.19, homogeneity 0.25).
The lesson is that silhouette score measures whether clusters are compact and separated, not whether they are meaningful. Optimising for it here would have selected the least informative model in the table.
Several methods score at or below zero on ARI. A negative Adjusted Rand Index means the partition agrees with the truth less than a random partition of the same shape would. K-Means and Ward both split the passengers cleanly in two — just not along the survival line. They are almost certainly separating by fare/class magnitude instead.
DBSCAN was the only method that chose its own cluster count. It found 7 clusters and flagged 34 points as noise, while every other method was told to produce 2. Its advantage on the external metrics may be partly a consequence of that extra freedom, so the comparison is informative rather than a fair ranking.
Overall conclusion: survival in this dataset is not recoverable from unsupervised structure in the standardised feature space. That is a real result about the data, not a failure of the pipeline — the passenger features cluster strongly by socio-economic profile, and survival cuts across those clusters.
pip install -r requirements.txt
python main.pyRegenerates every figure in figures/ and the full metric table in results/clustering_results.csv.
main.py whole pipeline: load → scale → cluster ×7 → score → plot
data/ input dataset
figures/ cluster scatter plots (PCA projection) + dendrograms
results/ clustering_results.csv
docs/report.pdf written report
requirements.txt numpy, pandas, matplotlib, scipy, scikit-learn
Author: Ali Erdem Gedik · github.com/aeg58