1.2 MiB
Raw Blame History

Бизнес-цель: кластеризация пациентов для выявления групп с схожими характеристиками здоровья и рисками инсульта. Что, к примеру, может использоваться для следующего:

  • определение, люди каких групп могут иметь бОльшую предрасположенность к возникновению инсульта
  • помощь в медицине на основе полученных данных в разработке медицинских показаний людям с повышенным риском возникновения инсульта
In [160]:
import pandas as pd
import numpy as np
from sklearn import cluster
from scipy.cluster import hierarchy

df1 = pd.read_csv("./csv/option4.csv", index_col='id')
df1.info
df = df1.head(2500)
df
Out[160]:
gender age hypertension heart_disease ever_married work_type Residence_type avg_glucose_level bmi smoking_status stroke
id
9046 Male 67.0 0 1 Yes Private Urban 228.69 36.6 formerly smoked 1
51676 Female 61.0 0 0 Yes Self-employed Rural 202.21 NaN never smoked 1
31112 Male 80.0 0 1 Yes Private Rural 105.92 32.5 never smoked 1
60182 Female 49.0 0 0 Yes Private Urban 171.23 34.4 smokes 1
1665 Female 79.0 1 0 Yes Self-employed Rural 174.12 24.0 never smoked 1
... ... ... ... ... ... ... ... ... ... ... ...
34383 Male 46.0 0 0 Yes Private Urban 88.23 25.8 Unknown 0
8646 Female 54.0 0 0 Yes Private Rural 97.47 26.7 never smoked 0
46653 Female 81.0 1 1 Yes Private Rural 59.28 28.1 never smoked 0
1099 Female 15.0 0 0 No children Rural 101.15 22.2 Unknown 0
61676 Male 77.0 0 0 Yes Self-employed Urban 68.38 25.1 Unknown 0

2500 rows × 11 columns

уберем пустые значения, подготовим данные:

In [161]:
print(df.isnull().sum())
print()

print(df.isnull().any())
print()
gender                 0
age                    0
hypertension           0
heart_disease          0
ever_married           0
work_type              0
Residence_type         0
avg_glucose_level      0
bmi                  119
smoking_status         0
stroke                 0
dtype: int64

gender               False
age                  False
hypertension         False
heart_disease        False
ever_married         False
work_type            False
Residence_type       False
avg_glucose_level    False
bmi                   True
smoking_status       False
stroke               False
dtype: bool

In [162]:
df['bmi'] = df['bmi'].fillna(df['bmi'].median())
print("\nНаличие пропущенных значений:")
print(df.isnull().sum())
df.describe()
Наличие пропущенных значений:
gender               0
age                  0
hypertension         0
heart_disease        0
ever_married         0
work_type            0
Residence_type       0
avg_glucose_level    0
bmi                  0
smoking_status       0
stroke               0
dtype: int64
C:\Users\elena\AppData\Local\Temp\ipykernel_68948\1629916119.py:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  df['bmi'] = df['bmi'].fillna(df['bmi'].median())
Out[162]:
age hypertension heart_disease avg_glucose_level bmi stroke
count 2500.000000 2500.000000 2500.000000 2500.000000 2500.000000 2500.000000
mean 44.605296 0.108000 0.062400 108.630440 29.102840 0.099600
std 22.817713 0.310443 0.241929 47.124712 7.804786 0.299526
min 0.080000 0.000000 0.000000 55.220000 10.300000 0.000000
25% 26.000000 0.000000 0.000000 77.902500 23.975000 0.000000
50% 47.000000 0.000000 0.000000 93.200000 28.200000 0.000000
75% 63.000000 0.000000 0.000000 117.510000 33.000000 0.000000
max 82.000000 1.000000 1.000000 271.740000 97.600000 1.000000
In [163]:
import matplotlib.pyplot as plt
import seaborn as sns
from typing import List, Any

def draw_data_2d(
    df: pd.DataFrame,
    col1: int,
    col2: int,
    y: List | None = None,
    classes: List | None = None,
    subplot: Any | None = None,
):
    ax = None
    if subplot is None:
        _, ax = plt.subplots()
    else:
        ax = subplot
    scatter = ax.scatter(df[df.columns[col1]], df[df.columns[col2]], c=y)
    ax.set(xlabel=df.columns[col1], ylabel=df.columns[col2])
    if classes is not None:
        ax.legend(
            scatter.legend_elements()[0], classes, loc="lower right", title="Classes"
        )

columns = ['age', 'avg_glucose_level', 'bmi', 'hypertension']
df_temp = df[columns]

sns.set_theme(style="whitegrid")
print("ЗАВИСИМОСТЬ ЗНАЧЕНИЙ ДРУГ ОТ ДРУГА")
plt.figure(figsize=(16,12))
draw_data_2d(df_temp, 0, 1, subplot=plt.subplot(2, 2, 1))  # age vs avg_glucose_level
plt.figure(figsize=(16,12))
draw_data_2d(df_temp, 0, 2, subplot=plt.subplot(2, 2, 2))  # age vs bmi
plt.figure(figsize=(16,12))
draw_data_2d(df_temp, 0, 3, subplot=plt.subplot(2, 2, 3))  # age vs hypertension
plt.figure(figsize=(16,12))
draw_data_2d(df_temp, 1, 2, subplot=plt.subplot(2, 2, 4))  # avg_glucose_level vs bmi
ЗАВИСИМОСТЬ ЗНАЧЕНИЙ ДРУГ ОТ ДРУГА
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

видно, что индекс массы тела в зависимости от возраста в основном держится поменьше в раннем возрасте (до полового созревания, грубо говоря), а потом уже распределяется от адекватного до 40+ (в общем, вплоть до ожирения, с выбросами-то)

потом гипертония встречается все таки после 20 лет чаще

ну и чем ниже индекс массы тела, тем ниже и адекватнее уровень глюкозы (ну тут ясно, почему. люди с избыточным весом и болеют диабетом чаще)

продолжим приводить данные к нормальному виду, и теперь их стандартизуем:

In [164]:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()

columns_to_scale = df_temp.drop(columns=["hypertension"]).columns
columns_to_keep = ["hypertension"]
data_scaled = scaler.fit_transform(df_temp[columns_to_scale])
df_scaled = pd.DataFrame(data_scaled, columns=columns_to_scale, index=df_temp.index)
df_scaled[columns_to_keep] = df_temp[columns_to_keep]

df_scaled
Out[164]:
age avg_glucose_level bmi hypertension
id
9046 0.981658 2.548208 0.960777 0
51676 0.718652 1.986183 -0.115701 0
31112 1.551505 -0.057528 0.435353 0
60182 0.192639 1.328647 0.678842 0
1665 1.507670 1.389985 -0.653940 1
... ... ... ... ...
34383 0.061136 -0.432990 -0.423266 0
8646 0.411811 -0.236875 -0.307929 0
46653 1.595339 -1.047440 -0.128516 1
1099 -1.297729 -0.158769 -0.884614 0
61676 1.420001 -0.854297 -0.512973 0

2500 rows × 4 columns

самое время применить иерархический алгоритм кластеризации (когда мы создаем дерево кластеров, где каждый уровень - это объединение более мелких кластеров)

In [165]:
# linkage_matrix = linkage(data_scaled, method='ward')
# plt.figure(figsize=(10,10))
# dendrogram(linkage_matrix)
# plt.title('Дендрограмма')
# plt.ylabel('')
# plt.xlabel('')
# plt.show()


import numpy as np
from sklearn import cluster
from scipy.cluster import hierarchy

def run_agglomerative(
    df: pd.DataFrame, num_clusters: int | None = 2
) -> cluster.AgglomerativeClustering:
    agglomerative = cluster.AgglomerativeClustering(
        n_clusters=num_clusters,
        compute_distances=True,
    )
    return agglomerative.fit(df)


def get_linkage_matrix(model: cluster.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)

def draw_dendrogram(linkage_matrix: np.ndarray):
    hierarchy.dendrogram(linkage_matrix, truncate_mode="level", p=3)
    plt.xticks(fontsize=10, rotation=45)
    plt.tight_layout()
In [166]:
tree = run_agglomerative(df_scaled)
linkage_matrix = get_linkage_matrix(tree)
draw_dendrogram(linkage_matrix)
No description has been provided for this image
In [167]:
result = hierarchy.fcluster(linkage_matrix, 40, criterion="distance")
y_names = ['0', '1', '2']

plt.figure(figsize=(12, 10))


draw_data_2d(df_temp, 0, 1, result, y_names, subplot=plt.subplot(2, 2, 1))  
draw_data_2d(df_temp, 0, 2, result, y_names, subplot=plt.subplot(2, 2, 2))  
draw_data_2d(df_temp, 0, 3, result, y_names, subplot=plt.subplot(2, 2, 3))  
draw_data_2d(df_temp, 1, 2, result, y_names, subplot=plt.subplot(2, 2, 4))
No description has been provided for this image

емае теперь переходим к НЕиерархической кластеризации будем использовать метод К-средних (K-means), мы выбираем количество кластеров и флгоритм пытается распределить данные так, чтобы минимизировать расстояние между объектами и центром их кластера

In [168]:
from typing import Tuple

def print_cluster_result(
    df: pd.DataFrame, clusters_num: int, labels: np.ndarray, separator: str = ", "
):
    for cluster_id in range(clusters_num):
        cluster_indices = np.where(labels == cluster_id)[0]
        print(f"Cluster {cluster_id + 1} ({len(cluster_indices)}):")
        rules = [str(df.index[idx]) for idx in cluster_indices]
        print(separator.join(rules))
        print("")
        print("--------")


def run_kmeans(
    df: pd.DataFrame, num_clusters: int, random_state: int
) -> Tuple[np.ndarray, np.ndarray]:
    kmeans = cluster.KMeans(n_clusters=num_clusters, random_state=random_state)
    labels = kmeans.fit_predict(df)
    return labels, kmeans.cluster_centers_
In [169]:
random_state = 9

labels, centers = run_kmeans(df_scaled, 3, random_state) 
print_cluster_result(df_scaled, 3, labels)
display(centers)
Cluster 1 (1314):
31112, 53882, 10434, 27419, 60491, 12109, 12095, 12175, 27458, 4219, 70822, 38047, 33879, 14248, 712, 24977, 47306, 62602, 4651, 1261, 61960, 1845, 37937, 47472, 35626, 36338, 18587, 15102, 59190, 47167, 38829, 55927, 65842, 19557, 7356, 17013, 72366, 6118, 7371, 70676, 27169, 19773, 66159, 71673, 42117, 57419, 26015, 26727, 66638, 70042, 32399, 3253, 71796, 14499, 49130, 51169, 66315, 37726, 54385, 35512, 8154, 4639, 12363, 4712, 33175, 2346, 42072, 30456, 59125, 56546, 48405, 36706, 71639, 60744, 7547, 5563, 68798, 72918, 50522, 3352, 70943, 48796, 16817, 31563, 55824, 20439, 45965, 8045, 37651, 41241, 62861, 72081, 32503, 12482, 56939, 43054, 34567, 50931, 16590, 3512, 42899, 43364, 44993, 210, 28939, 60739, 67432, 2182, 40899, 62466, 36841, 33486, 54567, 66204, 8003, 28378, 41081, 16077, 30184, 66071, 36255, 23410, 35684, 18937, 491, 8580, 28484, 62019, 51314, 37060, 35578, 54921, 33454, 62439, 2548, 2390, 68023, 54724, 8899, 39105, 31154, 69959, 10552, 12917, 68356, 28493, 1836, 32221, 10548, 17739, 27153, 34060, 43424, 30468, 56543, 15266, 10460, 64908, 67855, 25774, 49589, 17986, 29217, 72911, 47175, 48588, 66767, 29908, 45222, 40311, 71750, 42203, 71379, 58261, 67318, 8831, 65199, 43454, 7282, 49003, 16371, 40181, 66174, 6319, 55232, 41940, 72214, 37089, 52134, 54918, 1703, 16934, 32689, 18051, 38805, 61837, 49713, 17608, 62608, 4630, 66333, 49916, 71038, 58617, 69064, 9404, 28286, 10159, 58282, 64489, 64553, 69936, 46527, 13547, 9608, 10504, 37090, 60148, 52173, 23462, 11091, 70374, 31143, 66972, 55810, 37031, 34608, 36007, 48298, 44749, 46468, 51983, 20351, 55351, 67431, 20546, 52342, 59906, 53144, 11999, 38119, 3355, 67177, 58600, 65946, 48368, 36471, 15689, 8233, 23221, 31830, 15296, 17718, 18498, 56735, 621, 5835, 11838, 38165, 71585, 3009, 32361, 53910, 67548, 33404, 50965, 21077, 66570, 29158, 34299, 7696, 34668, 68483, 6072, 51112, 69673, 71238, 63958, 34511, 24892, 29496, 19939, 27832, 27757, 25099, 33123, 21713, 6726, 17242, 16380, 9729, 56974, 65574, 17019, 41800, 6855, 26028, 14712, 23094, 40622, 46438, 65144, 34641, 13129, 37629, 62936, 59829, 55424, 61697, 55138, 39399, 721, 40448, 58007, 11960, 24592, 67744, 8328, 32437, 55420, 53660, 56553, 30480, 31988, 45585, 52063, 27377, 7446, 65130, 30753, 22853, 12465, 64849, 24183, 39601, 46891, 38987, 21886, 5353, 44300, 46218, 39745, 13517, 36355, 22678, 52512, 3579, 3130, 5545, 63693, 33528, 11068, 62233, 7291, 36814, 48265, 10139, 12662, 43174, 72823, 30567, 21117, 50491, 61013, 71010, 23551, 12738, 57772, 16615, 68995, 53010, 967, 31145, 54338, 13223, 67932, 10255, 27012, 20541, 5892, 66883, 43196, 51514, 38184, 13997, 27796, 18390, 63409, 72882, 40866, 63561, 51422, 3590, 60665, 18430, 13365, 60983, 14615, 50277, 50811, 1246, 30712, 31308, 3325, 52808, 36109, 53336, 56831, 55592, 44583, 58227, 60810, 34612, 25595, 30550, 13367, 38609, 22159, 37413, 4169, 18888, 42503, 23645, 62382, 59521, 55386, 72547, 26973, 41033, 71442, 49624, 10572, 28910, 10381, 31956, 24665, 13683, 7387, 57011, 50053, 51125, 29077, 4970, 58291, 99, 64633, 23016, 18412, 67412, 37545, 14491, 66220, 25458, 69645, 53695, 26692, 33400, 67078, 22540, 26999, 30102, 49521, 29134, 68281, 40350, 39375, 12106, 25283, 49949, 28681, 62332, 25488, 14807, 16110, 40970, 28933, 11709, 16809, 13907, 54071, 28024, 11730, 17245, 70852, 60957, 19742, 4808, 49928, 52688, 65698, 820, 55721, 72310, 24115, 7122, 48755, 33551, 62716, 68438, 41148, 14924, 47950, 9262, 71896, 38623, 26503, 5475, 15525, 48748, 71591, 67864, 34857, 34995, 22952, 57879, 36638, 41097, 54620, 19681, 6988, 25287, 5934, 58999, 28261, 35222, 44105, 65256, 20044, 54769, 12686, 48830, 47924, 59336, 5684, 3673, 31867, 23633, 52549, 37349, 2751, 64464, 66494, 42786, 33401, 24174, 61715, 60663, 46875, 69091, 1821, 44978, 10762, 84, 45824, 61838, 57212, 62668, 33142, 17437, 38303, 36484, 60047, 16542, 18805, 17869, 6793, 49265, 6606, 23031, 22902, 4807, 9641, 10313, 12097, 45323, 39120, 68344, 66752, 5077, 49279, 42856, 10752, 42133, 4842, 58138, 65053, 24168, 61973, 18687, 72642, 54782, 24437, 65429, 3509, 15220, 4813, 31166, 9051, 28669, 59894, 18684, 35866, 51907, 7250, 37888, 42329, 27323, 72836, 66321, 53817, 32240, 28127, 40824, 29380, 65453, 9415, 65258, 62756, 49042, 66362, 10370, 156, 11105, 65667, 35231, 1893, 34728, 30352, 45497, 50371, 32687, 35295, 15746, 43268, 54540, 20973, 3532, 52550, 47414, 38804, 72861, 30944, 26191, 69312, 20162, 48989, 30411, 8598, 57347, 32645, 46643, 13602, 28326, 16906, 16837, 47585, 37404, 70678, 38649, 53266, 1191, 36820, 10133, 22566, 7055, 69177, 44764, 61983, 72268, 35927, 8727, 7516, 20425, 59878, 5858, 37053, 48073, 27145, 30328, 739, 28414, 70610, 62284, 22295, 27583, 9696, 1164, 48781, 50947, 47844, 49412, 43088, 16355, 43172, 65339, 60399, 22488, 16114, 35293, 26172, 67814, 12618, 39123, 53967, 34772, 43124, 68003, 59157, 54383, 6928, 321, 33526, 38350, 6040, 17639, 1678, 57668, 27966, 38123, 47345, 17222, 7195, 52457, 52306, 132, 8951, 64752, 51285, 14349, 66310, 58101, 28904, 6563, 55315, 65849, 31125, 5103, 67309, 2275, 15757, 38523, 65388, 60816, 67350, 40124, 20370, 35188, 28716, 56166, 47357, 33167, 21042, 71062, 49646, 24256, 62340, 39927, 17398, 20938, 21850, 43905, 62272, 62767, 3184, 69239, 42703, 39258, 48648, 71444, 35372, 31849, 2772, 11148, 50775, 69259, 12414, 21381, 68650, 57124, 19382, 24674, 72361, 36523, 1577, 32459, 7725, 67217, 49976, 42201, 11232, 14709, 57137, 51124, 42191, 35332, 36960, 12992, 62460, 41402, 63577, 52559, 66893, 742, 42902, 61512, 10943, 11447, 30746, 16949, 45297, 26452, 16378, 4559, 45257, 34386, 9076, 72824, 64132, 17827, 29378, 48609, 72474, 32094, 66818, 17860, 17078, 23836, 5296, 48184, 9511, 25559, 8096, 19735, 15310, 10245, 49023, 51020, 29095, 68994, 25935, 24567, 36679, 37759, 47558, 54264, 47893, 3178, 18141, 354, 5777, 46210, 36620, 21720, 6304, 18887, 57468, 24218, 69792, 6372, 34664, 30116, 35584, 2898, 10603, 1231, 25107, 32766, 9011, 14832, 49789, 33525, 12318, 54553, 45976, 12915, 4542, 60973, 68739, 3154, 22623, 47037, 48614, 15969, 17752, 50889, 56459, 34163, 14222, 31461, 47947, 51149, 17079, 53610, 48210, 8960, 63491, 51883, 20460, 47181, 1842, 34720, 9489, 28725, 13723, 60104, 48722, 14481, 67963, 14711, 36722, 55235, 20468, 44171, 8470, 13949, 61096, 19239, 70447, 37451, 29104, 26862, 61365, 35143, 5043, 26826, 16953, 51660, 27135, 16028, 49645, 71016, 62681, 41007, 33462, 33906, 43510, 21202, 7222, 13561, 29179, 5511, 20825, 67144, 69524, 28443, 50978, 45573, 64412, 3591, 25138, 29221, 6802, 8644, 54579, 41935, 17926, 64523, 11024, 11238, 19805, 34719, 48769, 38242, 42465, 24638, 58587, 36545, 19467, 16868, 23543, 65396, 23561, 57533, 59370, 57285, 23988, 31811, 26830, 25883, 61299, 12600, 35117, 28913, 42229, 23459, 2209, 38673, 42184, 59250, 29525, 42713, 29232, 70122, 66110, 69461, 60050, 21608, 32150, 24066, 39242, 57618, 27479, 10238, 67063, 33298, 48739, 40878, 12376, 26154, 47972, 43806, 39849, 1741, 20129, 1151, 6672, 11134, 25199, 66490, 33144, 16783, 727, 44177, 2421, 48693, 5723, 28309, 31806, 68750, 32840, 49797, 13503, 62238, 4627, 47208, 6844, 60001, 44503, 40371, 1460, 30285, 21472, 6537, 41827, 49775, 25777, 2070, 15752, 45915, 65697, 56889, 21724, 29863, 31999, 44202, 18704, 36518, 21521, 27163, 2447, 44391, 12741, 15418, 69482, 45399, 26247, 25818, 62817, 25919, 71978, 38316, 15647, 67689, 31689, 23240, 30850, 66080, 57263, 60126, 64393, 59642, 12064, 59737, 19352, 61903, 48453, 8031, 39139, 4838, 14889, 31746, 1499, 34396, 68816, 16129, 51845, 30692, 42161, 16113, 65109, 61242, 65252, 14089, 53399, 36946, 69069, 11539, 16847, 15873, 15415, 22891, 7394, 54997, 6199, 4635, 46261, 42624, 66680, 34248, 60210, 67890, 49254, 8345, 8770, 22370, 25930, 33478, 23009, 24885, 56420, 55220, 7384, 59745, 9644, 50837, 67941, 66051, 70783, 10716, 2868, 56324, 42047, 64980, 65962, 41501, 53032, 37320, 3842, 38143, 54296, 66677, 17950, 42830, 34721, 5157, 26084, 69623, 40378, 4671, 65419, 14406, 924, 71339, 394, 63362, 59928, 18680, 19439, 14099, 57774, 64033, 48472, 67956, 35602, 13818, 64895, 38320, 42040, 31857, 34764, 64817, 72450, 13988, 64371, 50295, 58645, 42599, 68370, 57813, 1329, 32974, 47600, 48246, 58086, 53957, 40137, 70500, 43872, 62951, 43244, 31198, 4591, 37150, 65632, 21826, 21036, 46923, 2265, 2860, 15964, 46483, 32166, 34188, 58359, 59347, 12849, 29694, 30806, 39956, 58543, 57549, 24289, 6206, 28227, 35229, 3045, 22386, 1077, 57903, 55982, 55465, 38432, 49666, 32365, 15351, 17466, 57569, 170, 10649, 28258, 22269, 56312, 26993, 58599, 61764, 13620, 39308, 34336, 1505, 60258, 63450, 43903, 15579, 43090, 12469, 58820, 45259, 9986, 46488, 54172, 21804, 36317, 3724, 69668, 59274, 29676, 37655, 16980, 40213, 47831, 39129, 40837, 59000, 44510, 3793, 32215, 35296, 27664, 49555, 68141, 30432, 6480, 22136, 2244, 61010, 12336, 3668, 68725, 464, 42225, 51254, 70429, 47937, 39593, 35378, 69835, 4709, 20393, 45864, 68685, 44962, 7892, 11744, 20740, 559, 68524, 34896, 44325, 3761, 65324, 34383, 8646, 46653, 61676

--------
Cluster 2 (813):
31720, 69768, 39912, 33943, 66866, 49669, 30669, 16523, 46136, 52800, 37893, 19584, 24447, 70336, 45801, 67210, 33759, 26325, 65460, 36811, 70970, 55680, 11014, 44338, 34974, 41648, 45538, 68249, 1686, 22284, 39038, 21956, 30171, 65535, 29865, 28799, 40840, 10449, 31091, 9487, 28102, 1506, 40670, 21284, 5973, 42996, 46785, 21408, 7559, 8171, 43232, 34402, 22706, 71539, 28637, 31741, 22537, 50611, 9637, 44862, 5708, 65357, 49465, 14123, 54975, 10913, 27029, 45719, 129, 530, 6107, 3655, 5010, 56681, 56716, 61350, 61465, 18108, 46436, 7351, 31164, 48272, 2893, 34376, 8595, 46474, 69687, 2953, 9179, 63050, 11974, 41523, 50441, 16927, 28265, 54375, 37832, 21058, 31279, 9201, 22622, 29933, 7621, 5374, 31564, 71808, 56998, 43134, 39383, 63606, 36331, 42359, 20751, 68241, 60902, 58439, 29010, 44912, 45238, 61511, 36942, 15095, 44315, 68245, 47732, 55709, 15311, 59807, 40639, 8544, 3361, 61408, 33552, 31364, 9906, 27794, 46809, 35565, 48144, 2532, 34363, 23650, 23046, 41927, 54866, 20364, 10997, 62999, 66184, 22870, 57523, 68131, 29873, 54182, 61300, 15274, 53016, 28848, 7745, 12593, 15553, 45796, 31840, 58767, 14391, 22321, 41673, 49086, 47523, 56870, 40791, 54304, 19234, 52454, 16575, 11176, 9612, 41513, 52580, 33723, 26235, 8320, 49529, 49785, 6886, 40055, 45283, 22685, 46745, 5046, 55847, 42441, 14387, 22384, 24108, 69427, 21688, 60777, 64732, 42710, 46683, 58909, 18616, 55529, 12204, 21397, 10324, 25514, 7663, 71793, 32352, 65218, 54643, 33410, 2543, 45289, 10792, 19153, 47876, 41615, 41537, 45759, 71929, 37154, 70380, 67405, 2549, 10782, 61742, 24099, 13948, 65766, 42482, 8008, 56089, 11745, 17733, 11743, 3606, 32554, 45893, 53538, 17006, 42108, 224, 56679, 27146, 16556, 36698, 57372, 30605, 13622, 39250, 2879, 59684, 56986, 16402, 40889, 4083, 48843, 5694, 44481, 19101, 11973, 59178, 44281, 55599, 45224, 54747, 6090, 46385, 46323, 28122, 50843, 60211, 53279, 37830, 2454, 3437, 6355, 58567, 62187, 72779, 12396, 69622, 58037, 34281, 7990, 57622, 11691, 13319, 53815, 51579, 58203, 6965, 42821, 10367, 66530, 43146, 57497, 16147, 18306, 61769, 26134, 66772, 41861, 954, 23565, 57854, 66678, 56734, 20347, 809, 67052, 69224, 13323, 59940, 46093, 46072, 47848, 71440, 59734, 32733, 61338, 59275, 19996, 31517, 56245, 9225, 45955, 53943, 53276, 39661, 51162, 4683, 782, 63565, 26389, 39518, 542, 26031, 38255, 41565, 39423, 68908, 28418, 33162, 39467, 20282, 51159, 7167, 59147, 18192, 14049, 69355, 2082, 16449, 5447, 44224, 533, 45554, 55744, 25767, 71319, 23604, 46576, 31293, 6044, 45209, 43155, 11882, 45669, 59604, 33187, 44192, 728, 28952, 51916, 21857, 55976, 27572, 54184, 4702, 45048, 30084, 50650, 40571, 13072, 22969, 47537, 26242, 36226, 32723, 35737, 30677, 50453, 14241, 40144, 13504, 51959, 2092, 68235, 3956, 34436, 40513, 48836, 62387, 3807, 51339, 32826, 44179, 14563, 40237, 65970, 51109, 5984, 13062, 47770, 12687, 36858, 50373, 13191, 47330, 64750, 70259, 72132, 11726, 13736, 43913, 41870, 37907, 15987, 57166, 47627, 8723, 937, 51806, 59412, 29233, 17762, 1405, 57953, 40251, 27013, 7586, 45357, 15219, 52987, 29327, 8085, 41820, 49057, 18070, 11770, 25454, 29224, 24219, 52089, 7297, 29910, 59339, 18754, 34312, 57798, 11605, 61924, 58015, 43271, 39714, 21785, 30214, 66419, 40931, 28559, 49815, 1625, 56309, 52034, 17175, 40544, 49152, 43672, 39286, 38043, 71721, 38094, 47350, 43675, 65801, 59953, 43772, 45754, 57485, 6128, 37082, 64541, 4538, 34001, 48964, 40393, 35432, 44010, 71044, 30290, 70752, 26366, 12436, 37698, 14677, 42743, 5686, 4789, 897, 69553, 38036, 36666, 16316, 31835, 4099, 26893, 1486, 5451, 3640, 17835, 37660, 24782, 63416, 42082, 54058, 4861, 33768, 35450, 62793, 66592, 29804, 3753, 27279, 38578, 66502, 9034, 16582, 28500, 70241, 66647, 39450, 57109, 17277, 18861, 38858, 13862, 66065, 71869, 46035, 54946, 29934, 28998, 63668, 24876, 22536, 8760, 53126, 18179, 68708, 12366, 38440, 34621, 16091, 17515, 34958, 30620, 1818, 70654, 49485, 61641, 11566, 72108, 22967, 33692, 25305, 7885, 14599, 38488, 52428, 61171, 2824, 2019, 47751, 34525, 13755, 56019, 67942, 52220, 48226, 10333, 10390, 72497, 51935, 29470, 71590, 16600, 41911, 3390, 72096, 41536, 17441, 737, 44938, 39011, 33412, 16061, 60266, 70965, 56736, 49480, 36704, 8884, 65229, 6596, 46577, 63455, 69249, 20310, 11450, 34133, 72311, 35651, 13749, 8882, 14287, 60139, 42500, 50983, 6493, 67099, 19585, 34261, 64128, 69339, 66546, 56584, 59933, 3429, 38920, 69285, 24428, 47701, 15225, 57236, 22689, 37752, 32320, 13964, 17492, 64006, 65712, 49615, 63511, 16987, 55522, 27954, 62607, 24404, 69666, 24342, 65093, 24735, 1679, 65336, 11573, 9199, 35402, 25996, 63219, 58591, 46363, 15440, 30731, 40471, 24721, 43590, 29014, 7868, 58350, 18927, 31372, 55262, 50238, 51343, 36486, 47582, 49627, 61291, 56791, 72514, 48435, 47607, 16535, 22414, 32252, 20565, 59993, 48851, 23413, 49970, 72414, 21374, 31443, 62289, 59464, 27017, 8277, 37128, 72701, 21969, 64494, 20673, 54985, 6049, 13380, 14404, 19419, 24518, 53494, 15255, 10584, 38675, 61743, 3879, 35085, 38474, 1451, 62834, 33284, 48875, 6104, 58253, 57679, 9197, 6968, 35838, 59200, 22108, 29258, 59904, 77, 54590, 52554, 12557, 2846, 61219, 65321, 23946, 20256, 27849, 33367, 1275, 31887, 35178, 9013, 60158, 8563, 61573, 43827, 31893, 63779, 71250, 55051, 2520, 21206, 60159, 3113, 62126, 51275, 3115, 35974, 44676, 40977, 67620, 63665, 33674, 10886, 67758, 41244, 50309, 27007, 37483, 29855, 66637, 22259, 19088, 6034, 61418, 59164, 54253, 66882, 54012, 28711, 58257, 36547, 13728, 4400, 24096, 65643, 30186, 11904, 20257, 2822, 18072, 53328, 8579, 29229, 48406, 1099

--------
Cluster 3 (373):
9046, 51676, 60182, 1665, 56669, 8213, 5317, 58202, 56112, 34120, 25226, 70630, 13861, 68794, 64778, 61843, 54827, 69160, 43717, 39373, 54401, 47269, 7937, 19824, 8752, 25831, 66400, 58631, 5111, 10710, 17004, 2326, 50784, 36236, 45805, 28291, 2458, 56841, 63973, 45277, 12062, 41069, 53401, 13491, 44033, 14164, 37132, 53440, 69551, 20387, 71279, 11762, 29281, 30683, 17308, 67981, 58978, 11933, 46703, 24669, 59437, 66258, 20426, 63453, 14431, 65105, 67895, 66955, 24905, 69112, 64373, 58267, 54695, 68627, 31179, 68025, 29552, 25904, 31421, 20463, 12689, 39186, 32729, 23368, 25974, 1210, 36857, 52282, 45535, 40460, 32257, 41413, 28674, 63884, 4057, 36275, 11577, 20980, 28526, 18518, 42807, 11120, 68614, 4480, 2982, 59368, 65836, 21130, 56357, 45053, 28333, 49421, 54312, 69037, 63732, 2374, 15528, 27213, 22320, 50305, 59729, 12985, 22091, 17291, 66196, 1307, 35846, 28645, 22470, 15649, 12982, 67733, 545, 15791, 67780, 68275, 36561, 47811, 17148, 56179, 25483, 50118, 39639, 31090, 64174, 48993, 39659, 71533, 34558, 42553, 53515, 9752, 49744, 22485, 16685, 25315, 33585, 17813, 64582, 12270, 50826, 14147, 2314, 63058, 13571, 47885, 17351, 25627, 72020, 36618, 37290, 62709, 7273, 10538, 9648, 66922, 8521, 69330, 5824, 8332, 55862, 42550, 14178, 69143, 67603, 34326, 18414, 17708, 38678, 30989, 22363, 41291, 33622, 47735, 55775, 35140, 2750, 62783, 19778, 22440, 32157, 28150, 6419, 39823, 32884, 70031, 5821, 45788, 52150, 37327, 56090, 22001, 16260, 35913, 40624, 45945, 54526, 29869, 47159, 7806, 63984, 5878, 239, 33983, 29375, 62452, 47622, 50098, 46373, 71318, 49341, 4692, 40253, 44950, 42460, 41271, 21491, 43059, 46284, 38493, 5137, 39202, 4833, 19389, 34496, 49709, 31415, 71322, 72337, 7550, 57917, 41424, 54858, 49495, 15166, 16593, 63663, 15988, 35829, 53909, 5799, 16488, 44781, 29385, 48072, 32776, 50841, 26328, 52419, 70344, 6879, 58438, 12512, 2513, 45713, 24272, 54347, 54353, 15515, 48759, 32452, 35333, 15120, 11412, 24630, 24229, 9170, 47608, 63597, 5478, 43657, 71917, 24603, 70857, 16066, 48069, 49014, 61247, 27799, 72435, 46864, 25405, 7344, 61178, 48364, 71182, 48775, 8968, 32016, 32270, 1473, 60963, 66431, 36750, 16938, 29388, 5355, 29915, 3305, 50671, 68333, 44777, 36377, 39531, 14479, 53422, 19550, 62456, 47521, 63938, 45040, 42212, 57270, 63401, 53990, 17295, 55466, 34448, 49672, 59130, 34661, 65680, 5863, 23223, 55566, 63990, 61895, 36589, 28651, 45033, 20316, 7683, 23176, 61000, 9026, 54301, 3099, 46068, 3715, 50402, 69502, 16812, 62629, 63912, 49574, 7411, 6239, 44591, 27626, 12279, 28303, 7658, 35997

--------
array([[ 0.47644409, -0.40065839,  0.33339772,  0.12947449],
       [-1.10132351, -0.3102823 , -0.77003252,  0.004914  ],
       [ 0.72629021,  2.08749131,  0.50685056,  0.25737265]])
In [170]:
def draw_cluster_results(
    df: pd.DataFrame,
    col1: int,
    col2: int,
    labels: np.ndarray,
    cluster_centers: np.ndarray,
    subplot: Any | None = None,
):
    ax = None
    if subplot is None:
        ax = plt
    else:
        ax = subplot

    centroids = cluster_centers
    u_labels = np.unique(labels)

    for i in u_labels:
        ax.scatter(
            df[labels == i][df.columns[col1]],
            df[labels == i][df.columns[col2]],
            label=i,
        )

    ax.scatter(centroids[:, col1], centroids[:, col2], s=80, color="k")
    plt.title('Точка - это кластер, грубо говоря (центр кластера) :)')


plt.figure(figsize=(16, 12))
draw_cluster_results(df_scaled, 0, 1, labels, centers, plt.subplot(2, 2, 1)) # age vs avg_glucose_level
draw_cluster_results(df_scaled, 0, 2, labels, centers, plt.subplot(2, 2, 2)) # age vs bmi
draw_cluster_results(df_scaled, 0, 3, labels, centers, plt.subplot(2, 2, 3)) # age vs hypertension
draw_cluster_results(df_scaled, 1, 2, labels, centers, plt.subplot(2, 2, 4)) # avg_glucose_level vs bmi
No description has been provided for this image
In [172]:
from sklearn.decomposition import PCA

#до двухмерного пространсва :) вжух
pca_data = PCA(n_components=2).fit_transform(df_scaled)
pca_data

# Визуализация сокращенных данных
plt.figure(figsize=(16, 6))

# Визуализация для KMeans кластеризации
plt.subplot(1, 2, 1)
sns.scatterplot(x=pca_data[:, 0], y=pca_data[:, 1], hue=labels, palette='Set1', alpha=0.6)
plt.title('PCA Reduced Data: KMeans Clustering')

plt.tight_layout()
plt.show()
No description has been provided for this image

теперь интересная штука... с помощью так называемого метода локтя посмотрим на лучшее (оптимальное) количество кластеров на основе инерции (расстояния = сумме квадратов расстояния от объектов до центра кластера)

In [184]:
from sklearn.cluster import KMeans

inertias = []
clusters_range = range(1, 23)
for i in clusters_range:
    kmeans = KMeans(n_clusters=i, random_state=random_state)
    kmeans.fit(data_scaled)
    inertias.append(kmeans.inertia_)


plt.figure(figsize=(10, 6))
plt.plot(clusters_range, inertias, marker='*')
plt.title('Метод локтя для оптимального k')
plt.xlabel('Количество кластеров')
plt.ylabel('Инерция')
plt.grid(True)
plt.show()
No description has been provided for this image

отсюда можем видеть, что кривая, в принципе, прекращает резко падать после 15 кластера. а в принципе, САМЫЙ резкий спад закончился на количесте кластеров,равному 3-5

ТЕПЕРЬ ЧАВО ой капс

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

In [186]:
from sklearn.metrics import silhouette_score

silhouette_scores = []
for i in clusters_range[1:]:  
    kmeans = KMeans(n_clusters=i, random_state=random_state)
    labels = kmeans.fit_predict(data_scaled)
    score = silhouette_score(data_scaled, labels)
    silhouette_scores.append(score)

# Построение диаграммы значений силуэта
plt.figure(figsize=(10, 6))
plt.plot(clusters_range[1:], silhouette_scores, marker='4')
plt.title('Коэффициенты силуэта для разных k')
plt.xlabel('Количество кластеров')
plt.ylabel('Коэффициент силуэта')
plt.grid(True)
plt.show()
No description has been provided for this image

видим, что при количестве кластеров, равном трем, самое лучшее разбиение получается. вот и отличненько) ведь я как раз разбивала данные на 3 кластера

In [ ]: