Total Pageviews

Thursday, October 1, 2026

kmedoid

K-Medoids Clustering

Theory, Python Implementation and Comparison with K-Means

1. What is K-Medoids?

K-Medoids is an unsupervised machine learning clustering algorithm. It divides a dataset into a predefined number of groups called clusters.

The main idea of K-Medoids is to select an actual observation from the dataset as the representative point of each cluster. This representative point is called a medoid.

Important: A medoid must always be an actual data point from the dataset.

How K-Medoids Works

  1. Choose the number of clusters, K.
  2. Select K initial medoids.
  3. Calculate the distance between every data point and every medoid.
  4. Assign each data point to its nearest medoid.
  5. Calculate the total clustering cost.
  6. Try replacing a medoid with another data point.
  7. If the replacement reduces the cost, keep the replacement.
  8. Repeat until no useful replacement improves the clustering.

Manhattan Distance

In the example below, Manhattan distance is used.

Distance = |X₂ − X₁| + |Y₂ − Y₁|

Example

Suppose the medoid is (9,3) and the point is (8,4).

Distance = |8 − 9| + |4 − 3| = 1 + 1 = 2

Therefore, the distance between the two points is 2.

2. Dataset Used in the Example

The following 10-point dataset is used for both K-Means and K-Medoids comparison.

Point X Y
P193
P284
P346
P485
P525
P638
P758
P844
P9104
P1096
Number of clusters K = 2
Initial Medoid 1 = (4,6)
Initial Medoid 2 = (9,3)

3. Python Implementation of K-Medoids

The following code implements K-Medoids using the same dataset. It uses Manhattan distance and creates two clusters.

# ==========================================
# K-MEDOIDS CLUSTERING
# ==========================================

# Install library in Google Colab
!pip install scikit-learn-extra -q

# Import libraries
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from sklearn_extra.cluster import KMedoids


# Dataset
data = np.array([
    [9, 3],
    [8, 4],
    [4, 6],
    [8, 5],
    [2, 5],
    [3, 8],
    [5, 8],
    [4, 4],
    [10, 4],
    [9, 6]
])


# Create DataFrame
df = pd.DataFrame(data, columns=["X", "Y"])

print("Dataset:")
print(df)


# Number of clusters
k = 2


# Create K-Medoids model
model = KMedoids(
    n_clusters=k,
    metric="manhattan",
    random_state=42
)


# Train model
model.fit(data)


# Cluster labels
labels = model.labels_

print("\nCluster Labels:")
print(labels)


# Get medoids
medoid_indices = model.medoid_indices_
medoids = data[medoid_indices]

print("\nMedoids:")

for i, medoid in enumerate(medoids):
    print(
        "Medoid", i + 1,
        "=", tuple(medoid)
    )


# Display clusters

for cluster in range(k):

    print("\nCluster", cluster + 1)

    cluster_points = data[labels == cluster]

    print(cluster_points)


# Total clustering cost
print("\nTotal Cost:")
print(model.inertia_)


# Plot clusters

plt.figure(figsize=(9, 7))

for cluster in range(k):

    points = data[labels == cluster]

    plt.scatter(
        points[:, 0],
        points[:, 1],
        s=100,
        label=f"Cluster {cluster + 1}"
    )


# Plot medoids
plt.scatter(
    medoids[:, 0],
    medoids[:, 1],
    s=250,
    marker="X",
    label="Medoids"
)


# Point labels
for i, point in enumerate(data):

    plt.annotate(
        f"P{i + 1}",
        (point[0], point[1]),
        xytext=(5, 5),
        textcoords="offset points"
    )


plt.xlabel("X")
plt.ylabel("Y")
plt.title("K-Medoids Clustering")

plt.legend()
plt.grid(True)

plt.show()

4. K-Means vs K-Medoids

Both algorithms are clustering techniques, but they calculate their cluster representatives differently.

Feature K-Means K-Medoids
Type Unsupervised Unsupervised
Representative Centroid Medoid
Representative is actual data point? No Yes
Center calculation Mean Actual observation
Distance in this example Euclidean Manhattan
Effect of outliers More sensitive Generally more robust
Speed Usually faster Usually more computationally expensive
Center can be a new point? Yes No
K-Means:
Calculates the average of points to create a centroid.

K-Medoids:
Selects an existing observation as the medoid.

5. Result Comparison for This Dataset

Cluster K-Means K-Medoids
Cluster 1 P3, P5, P6, P7, P8 P3, P5, P6, P7, P8
Cluster 2 P1, P2, P4, P9, P10 P1, P2, P4, P9, P10
Cluster 1 Representative (3.6, 6.2) (4, 6)
Cluster 2 Representative (8.8, 4.4) (9, 3)
Important observation: For this dataset and initialization, both methods produce the same two groups, but their representatives are different.

K-Means produces the new centroids:

C1 = (3.6, 6.2)     C2 = (8.8, 4.4)

K-Medoids uses actual observations:

M1 = (4, 6)     M2 = (9, 3)

6. Single Python Program: K-Means + K-Medoids

The following program performs both algorithms on the same dataset and displays their results side-by-side.

# ==========================================================
# K-MEANS AND K-MEDOIDS ON THE SAME DATASET
# ==========================================================

# Install K-Medoids library in Google Colab
!pip install scikit-learn-extra -q


# ----------------------------------------------------------
# IMPORT LIBRARIES
# ----------------------------------------------------------

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from sklearn.cluster import KMeans
from sklearn_extra.cluster import KMedoids


# ----------------------------------------------------------
# DATASET
# ----------------------------------------------------------

data = np.array([
    [9, 3],
    [8, 4],
    [4, 6],
    [8, 5],
    [2, 5],
    [3, 8],
    [5, 8],
    [4, 4],
    [10, 4],
    [9, 6]
])


# ----------------------------------------------------------
# DISPLAY DATASET
# ----------------------------------------------------------

df = pd.DataFrame(
    data,
    columns=["X", "Y"]
)

print("ORIGINAL DATASET")
print(df)


# ----------------------------------------------------------
# NUMBER OF CLUSTERS
# ----------------------------------------------------------

K = 2


# ==========================================================
# K-MEANS
# ==========================================================

kmeans = KMeans(
    n_clusters=K,
    init=np.array([
        [4, 6],
        [9, 3]
    ]),
    n_init=1,
    random_state=42
)

kmeans.fit(data)


# K-Means labels
kmeans_labels = kmeans.labels_


# K-Means centroids
kmeans_centroids = kmeans.cluster_centers_


# K-Means cost
kmeans_cost = kmeans.inertia_


print("\n")
print("=" * 50)
print("K-MEANS RESULTS")
print("=" * 50)

print("\nCluster Labels:")
print(kmeans_labels)

print("\nCentroids:")

for i, centroid in enumerate(kmeans_centroids):

    print(
        "Centroid", i + 1,
        "=", tuple(np.round(centroid, 2))
    )

print("\nK-Means SSE:")
print(round(kmeans_cost, 2))


# Display K-Means clusters

for cluster in range(K):

    print("\nK-Means Cluster", cluster + 1)

    points = data[kmeans_labels == cluster]

    print(points)


# ==========================================================
# K-MEDOIDS
# ==========================================================

kmedoids = KMedoids(
    n_clusters=K,
    metric="manhattan",
    init=np.array([
        [4, 6],
        [9, 3]
    ]),
    random_state=42
)

kmedoids.fit(data)


# K-Medoids labels
kmedoids_labels = kmedoids.labels_


# K-Medoids medoid indices
medoid_indices = kmedoids.medoid_indices_


# K-Medoids medoids
kmedoids_medoids = data[medoid_indices]


# K-Medoids cost
kmedoids_cost = kmedoids.inertia_


print("\n")
print("=" * 50)
print("K-MEDOIDS RESULTS")
print("=" * 50)

print("\nCluster Labels:")
print(kmedoids_labels)

print("\nMedoids:")

for i, medoid in enumerate(kmedoids_medoids):

    print(
        "Medoid", i + 1,
        "=", tuple(medoid)
    )

print("\nK-Medoids Cost:")
print(kmedoids_cost)


# Display K-Medoids clusters

for cluster in range(K):

    print("\nK-Medoids Cluster", cluster + 1)

    points = data[kmedoids_labels == cluster]

    print(points)


# ==========================================================
# SIDE-BY-SIDE COMPARISON
# ==========================================================

print("\n")
print("=" * 70)
print("K-MEANS vs K-MEDOIDS")
print("=" * 70)

print("\nK-MEANS")

for cluster in range(K):

    points = data[kmeans_labels == cluster]

    print(
        "Cluster",
        cluster + 1,
        ":",
        [tuple(p) for p in points]
    )


print("\nK-MEDOIDS")

for cluster in range(K):

    points = data[kmedoids_labels == cluster]

    print(
        "Cluster",
        cluster + 1,
        ":",
        [tuple(p) for p in points]
    )


print("\nK-Means Centroids:")

for centroid in kmeans_centroids:

    print(tuple(np.round(centroid, 2)))


print("\nK-Medoids Medoids:")

for medoid in kmedoids_medoids:

    print(tuple(medoid))


# ==========================================================
# PLOT K-MEANS
# ==========================================================

plt.figure(figsize=(8, 6))

for cluster in range(K):

    points = data[kmeans_labels == cluster]

    plt.scatter(
        points[:, 0],
        points[:, 1],
        s=100,
        label=f"Cluster {cluster + 1}"
    )


plt.scatter(
    kmeans_centroids[:, 0],
    kmeans_centroids[:, 1],
    s=250,
    marker="X",
    label="Centroids"
)


for i, point in enumerate(data):

    plt.annotate(
        f"P{i + 1}",
        (point[0], point[1]),
        xytext=(5, 5),
        textcoords="offset points"
    )


plt.xlabel("X")
plt.ylabel("Y")
plt.title("K-Means Clustering")
plt.legend()
plt.grid(True)

plt.show()


# ==========================================================
# PLOT K-MEDOIDS
# ==========================================================

plt.figure(figsize=(8, 6))

for cluster in range(K):

    points = data[kmedoids_labels == cluster]

    plt.scatter(
        points[:, 0],
        points[:, 1],
        s=100,
        label=f"Cluster {cluster + 1}"
    )


plt.scatter(
    kmedoids_medoids[:, 0],
    kmedoids_medoids[:, 1],
    s=250,
    marker="X",
    label="Medoids"
)


for i, point in enumerate(data):

    plt.annotate(
        f"P{i + 1}",
        (point[0], point[1]),
        xytext=(5, 5),
        textcoords="offset points"
    )


plt.xlabel("X")
plt.ylabel("Y")
plt.title("K-Medoids Clustering")
plt.legend()
plt.grid(True)

plt.show()

7. Conclusion

K-Means and K-Medoids are both unsupervised clustering algorithms used to divide observations into groups.

  • K-Means calculates a centroid using the mean of the observations in a cluster.
  • K-Medoids selects an actual observation as the representative of a cluster.
  • In this example, both methods produce the same two groups.
  • However, K-Means produces new center points, whereas K-Medoids uses existing observations.
  • K-Medoids can be useful when the use of an actual observation as the cluster representative is important.
Easy way to remember:

K-Means → Mean = Centroid
K-Medoids → Existing Data Point = Medoid

No comments:

Post a Comment