Skip to content

Alt text source: @allison_horst https://github.com/allisonhorst/penguins

You have been asked to support a team of researchers who have been collecting data about penguins in Antartica! The data is available in csv-Format as penguins.csv

Origin of this data : Data were collected and made available by Dr. Kristen Gorman and the Palmer Station, Antarctica LTER, a member of the Long Term Ecological Research Network.

The dataset consists of 5 columns.

ColumnDescription
culmen_length_mmculmen length (mm)
culmen_depth_mmculmen depth (mm)
flipper_length_mmflipper length (mm)
body_mass_gbody mass (g)
sexpenguin sex

Unfortunately, they have not been able to record the species of penguin, but they know that there are at least three species that are native to the region: Adelie, Chinstrap, and Gentoo. Your task is to apply your data science skills to help them identify groups in the dataset!

# Import Required Packages
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler

# Loading and examining the dataset
penguins_df = pd.read_csv("penguins.csv")
penguins_df.head()
penguin_dummies = pd.get_dummies(penguins_df['sex'], drop_first=True)
penguin_dummies = pd.concat([penguins_df, penguin_dummies], axis=1)
penguin_dummies = penguin_dummies.drop('sex', axis=1)
scaler = StandardScaler()
penguin_scaled = scaler.fit_transform(penguin_dummies)
penguin_scaled
inertias = []
ks = range(1,10)
for k in ks:
    kmeans = KMeans(n_clusters=k, random_state=42).fit(penguin_scaled)
    inertias.append(kmeans.inertia_)

# --- Visualization ---
plt.figure(figsize=(7, 5))
plt.plot(list(ks), inertias, marker='o')
plt.xticks(list(ks))
plt.xlabel("Number of clusters (k)")
plt.ylabel("Inertia")
plt.title("Elbow Analysis (KMeans)")
plt.grid(True, linestyle="--", alpha=0.5)
plt.show()
    
kmean_optimal = KMeans(n_clusters=6, random_state=42)
kmean_optimal.fit(penguin_scaled)

labels = kmeans.labels_
penguins_df['label'] = labels


# 2️⃣ Choose interpretable features to plot
x_col = "culmen_length_mm"
y_col = "culmen_depth_mm"

# ===============================
# 4️⃣ Visualize the clusters (for 2D data)
# ===============================
plt.figure(figsize=(8,6))
plt.scatter(
    penguins_df[x_col],
    penguins_df[y_col],
    c=penguins_df["label"],
    cmap="viridis",
    alpha=0.7,
    s=60
)

plt.title("K-Means Clustering of Penguins (k=6)")
plt.xlabel(x_col)
plt.ylabel(y_col)
plt.colorbar(label="Cluster")
plt.grid(True, linestyle="--", alpha=0.5)
plt.show()
import numpy as np
# 1) Identify numeric (non-binary) columns
num_cols = penguins_df.select_dtypes(include=[np.number]).columns.tolist()

# treat as binary if the column has only two unique values and those are {0,1}
binary_like = []
for c in num_cols:
    vals = penguins_df[c].dropna().unique()
    if len(vals) <= 2 and set(np.unique(vals)).issubset({0, 1}):
        binary_like.append(c)

numeric_columns = [c for c in num_cols if c not in binary_like]

# 2) Attach cluster labels to the original DataFrame
penguins_df = penguins_df.copy()
penguins_df["label"] = kmeans.labels_

# 3) Final characteristic DataFrame (means per cluster)
stat_penguins = (
    penguins_df
    .groupby("label")[numeric_columns]
    .mean()
    .round(3)
)

# (Optional) Add cluster sizes as the first column
cluster_sizes = penguins_df.groupby("label").size().rename("n")
stat_penguins = cluster_sizes.to_frame().join(stat_penguins)

# 4) Done — inspect
print("Numeric (non-binary) columns used:", numeric_columns)
print("\nFinal characteristic table (means):")
print(stat_penguins)