2024-12-13 21:57:58 +04:00

450 KiB
Raw Permalink Blame History

In [3]:
import pandas as pd
df = pd.read_csv("..//static//csv//ds_salaries.csv")
df
Out[3]:
work_year experience_level employment_type job_title salary salary_currency salary_in_usd employee_residence remote_ratio company_location company_size
0 2023 SE FT Principal Data Scientist 80000 EUR 85847 ES 100 ES L
1 2023 MI CT ML Engineer 30000 USD 30000 US 100 US S
2 2023 MI CT ML Engineer 25500 USD 25500 US 100 US S
3 2023 SE FT Data Scientist 175000 USD 175000 CA 100 CA M
4 2023 SE FT Data Scientist 120000 USD 120000 CA 100 CA M
... ... ... ... ... ... ... ... ... ... ... ...
3750 2020 SE FT Data Scientist 412000 USD 412000 US 100 US L
3751 2021 MI FT Principal Data Scientist 151000 USD 151000 US 100 US L
3752 2020 EN FT Data Scientist 105000 USD 105000 US 100 US S
3753 2020 EN CT Business Data Analyst 100000 USD 100000 US 100 US L
3754 2021 SE FT Data Science Manager 7000000 INR 94665 IN 50 IN L

3755 rows × 11 columns

Цель работы

Я буду кластеризовать данные сотрудников на основе их характеристик для выделения групп с общими профессиональными и экономическими признаками. Это может быть полезно для анализа рынка труда, планирования кадровой стратегии или разработки программ по удержанию и привлечению специалистов

Не много бработаем данные

In [ ]:
from sklearn.preprocessing import StandardScaler

# Преобразование категориальных данных в числовые с помощью one-hot encoding
df = pd.get_dummies(df, drop_first=True)

# Сделаем данные сравнивыми 
scaler = StandardScaler()
df_scaled = scaler.fit_transform(df)

df_scaled
Out[ ]:
array([[ 0.90599446, -0.16482684, -0.82039118, ..., -0.01632123,
        -2.28856757, -0.20256191],
       [ 0.90599446, -0.23927735, -1.70618745, ..., -0.01632123,
        -2.28856757,  4.93676226],
       [ 0.90599446, -0.2459779 , -1.77756251, ..., -0.01632123,
        -2.28856757,  4.93676226],
       ...,
       [-3.43330297, -0.12760158, -0.51660304, ..., -0.01632123,
        -2.28856757,  4.93676226],
       [-3.43330297, -0.13504663, -0.59590867, ..., -0.01632123,
        -2.28856757, -0.20256191],
       [-1.9868705 , 10.13912397, -0.68052777, ..., -0.01632123,
        -2.28856757, -0.20256191]])

Используем PCA(анализ главных компонент) для визуализации данных

In [9]:
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt

# Применяем PCA для снижения размерности до 2
pca = PCA(n_components=2)
df_pca = pca.fit_transform(df_scaled)

# Визуализация
plt.figure(figsize=(8, 6))
plt.scatter(df_pca[:, 0], df_pca[:, 1], c='blue', edgecolor='k', alpha=0.6)
plt.title("PCA: Визуализация данных после снижения размерности")
plt.xlabel("Главная компонента 1")
plt.ylabel("Главная компонента 2")
plt.show()
No description has been provided for this image

Определение оптимального количества кластеров

In [10]:
# Метод локтя
from sklearn.cluster import KMeans

border_l = 2
border_r = 5

inertia = []
for k in range(border_l, border_r):
    kmeans = KMeans(n_clusters=k, random_state=42)
    kmeans.fit(df_scaled)
    inertia.append(kmeans.inertia_)

# Визуализация метода локтя
plt.figure(figsize=(8, 6))
plt.plot(range(border_l, border_r), inertia, marker='o')
plt.title('Метод локтя для выбора количества кластеров')
plt.xlabel('Количество кластеров')
plt.ylabel('Инерция')
plt.show()

# Коэффициент силуэта
from sklearn.metrics import silhouette_score

silhouette_scores = []
for k in range(border_l, border_r):
    kmeans = KMeans(n_clusters=k, random_state=42)
    kmeans.fit(df_scaled)
    score = silhouette_score(df_scaled, kmeans.labels_)
    silhouette_scores.append(score)

# Визуализация коэффициента силуэта
plt.figure(figsize=(8, 6))
plt.plot(range(border_l, border_r), silhouette_scores, marker='o')
plt.title('Коэффициент силуэта для различных кластеров')
plt.xlabel('Количество кластеров')
plt.ylabel('Коэффициент силуэта')
plt.show()
No description has been provided for this image
No description has been provided for this image

Кластеризация с помощью K-means(группирует данные вокруг центров (центроидов) кластеров)

In [11]:
# Кластеризация с помощью K-means
optimal_clusters = 3
kmeans = KMeans(n_clusters=optimal_clusters, random_state=42)
df['Cluster'] = kmeans.fit_predict(df_scaled)

# Визуализация кластеров с использованием PCA
plt.figure(figsize=(8, 6))
plt.scatter(df_pca[:, 0], df_pca[:, 1], c=df['Cluster'], cmap='viridis', edgecolor='k', alpha=0.6)
plt.title("Кластеры, определенные K-means (PCA)")
plt.xlabel("Главная компонента 1")
plt.ylabel("Главная компонента 2")
plt.colorbar(label='Кластер')
plt.show()
No description has been provided for this image

Иерархическая кластеризация

Иерархическая кластеризация — метод, который строит древовидную структуру кластеров (дендрограмму).

In [12]:
from sklearn.cluster import AgglomerativeClustering
from scipy.cluster.hierarchy import dendrogram
import numpy as np
import matplotlib.pyplot as plt

# Применение иерархической кластеризации
hierarchical = AgglomerativeClustering(n_clusters=optimal_clusters, compute_distances=True)
df['Hierarchical Cluster'] = hierarchical.fit_predict(df_scaled)

# Функция для получения матрицы linkage
def get_linkage_matrix(model: AgglomerativeClustering) -> np.ndarray:
    counts = np.zeros(model.children_.shape[0])  # type: ignore
    n_samples = len(model.labels_)
    for i, merge in enumerate(model.children_):  # type: ignore
        current_count = 0
        for child_idx in merge:
            if child_idx < n_samples:
                current_count += 1
            else:
                current_count += counts[child_idx - n_samples]
        counts[i] = current_count

    return np.column_stack([model.children_, model.distances_, counts]).astype(float)

# Построение дендрограммы
linkage_matrix = get_linkage_matrix(hierarchical)
plt.figure(figsize=(12, 8))
dendrogram(linkage_matrix)
plt.title("Дендограмма, восстановленная из модели AgglomerativeClustering")
plt.xlabel("Индексы объектов")
plt.ylabel("Евклидово расстояние")
plt.show()


# Визуализация кластеров
plt.figure(figsize=(8, 6))
plt.scatter(df_pca[:, 0], df_pca[:, 1], c=df['Hierarchical Cluster'], cmap='viridis', edgecolor='k', alpha=0.6)
plt.title("Кластеры, определенные иерархической кластеризацией (PCA)")
plt.xlabel("Главная компонента 1")
plt.ylabel("Главная компонента 2")
plt.colorbar(label='Кластер')
plt.show()
No description has been provided for this image
No description has been provided for this image

Оценка качества кластеризации

Оценим качество кластеров, сравнив коэффициенты силуэта для двух методов.

In [13]:
# Оценка качества
silhouette_kmeans = silhouette_score(df_scaled, df['Cluster'])
silhouette_hierarchical = silhouette_score(df_scaled, df['Hierarchical Cluster'])

print(f"Коэффициент силуэта для K-means: {silhouette_kmeans:.4f}")
print(f"Коэффициент силуэта для иерархической кластеризации: {silhouette_hierarchical:.4f}")
Коэффициент силуэта для K-means: 0.7657
Коэффициент силуэта для иерархической кластеризации: 0.4890

Можно сделать вывод:

K-means и иерархическая кластеризация дают схожие результаты, но могут отличаться по точности в зависимости от структуры данных.

Как интерпретировать значения?
Коэффициент силуэта находится в диапазоне от -1 до 1:

Близко к 1: Отличные кластеры (чётко разделённые).
Около 0: Кластеры пересекаются или слабо разделены.
Меньше 0: Объекты часто попадают не в свои кластеры.

K-means = 0.7657 успешно справился с задачей кластеризации, сформировав чётко разделённые кластеры.

Иерархическая кластеризация показала средний результат с коэффициентом силуэта 0.4890, что указывает на менее чётко сформированные кластеры.