Nikolas Cantillo
Caso cirrosis / Notebookscikit-learn · SMOTE · K-Prototypes

El notebook, celda por celda

Análisis completo sobre el dataset de cirrosis de Mayo Clinic tal cual fue desarrollado: exploración clínica, balanceo de clases con SMOTE, comparación de clasificadores para predecir el desenlace del paciente y segmentación con clustering. Código y resultados reales; se omite la cabecera institucional del curso.

In [1]Python
data.info()
Out
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 418 entries, 0 to 417
Data columns (total 20 columns):
 #   Column         Non-Null Count  Dtype  
---  ------         --------------  -----  
 0   ID             418 non-null    int64  
 1   N_Days         418 non-null    int64  
 2   Status         418 non-null    object 
 3   Drug           312 non-null    object 
 4   Age            418 non-null    int64  
 5   Sex            418 non-null    object 
 6   Ascites        312 non-null    object 
 7   Hepatomegaly   312 non-null    object 
 8   Spiders        312 non-null    object 
 9   Edema          418 non-null    object 
 10  Bilirubin      418 non-null    float64
 11  Cholesterol    284 non-null    float64
 12  Albumin        418 non-null    float64
 13  Copper         310 non-null    float64
 14  Alk_Phos       312 non-null    float64
 15  SGOT           312 non-null    float64
 16  Tryglicerides  282 non-null    float64
 17  Platelets      407 non-null    float64
 18  Prothrombin    416 non-null    float64
 19  Stage          412 non-null    float64
dtypes: float64(10), int64(3), object(7)
memory usage: 65.4+ KB
In [2]Python
max_nans_allowed = 3
df = data.dropna(thresh=data.shape[1] - max_nans_allowed)
df = df.drop(columns=['ID'])
In [3]Python
df.info()
Out
<class 'pandas.core.frame.DataFrame'>
Index: 312 entries, 0 to 311
Data columns (total 19 columns):
 #   Column         Non-Null Count  Dtype  
---  ------         --------------  -----  
 0   N_Days         312 non-null    int64  
 1   Status         312 non-null    object 
 2   Drug           312 non-null    object 
 3   Age            312 non-null    int64  
 4   Sex            312 non-null    object 
 5   Ascites        312 non-null    object 
 6   Hepatomegaly   312 non-null    object 
 7   Spiders        312 non-null    object 
 8   Edema          312 non-null    object 
 9   Bilirubin      312 non-null    float64
 10  Cholesterol    284 non-null    float64
 11  Albumin        312 non-null    float64
 12  Copper         310 non-null    float64
 13  Alk_Phos       312 non-null    float64
 14  SGOT           312 non-null    float64
 15  Tryglicerides  282 non-null    float64
 16  Platelets      308 non-null    float64
 17  Prothrombin    312 non-null    float64
 18  Stage          312 non-null    float64
dtypes: float64(10), int64(2), object(7)
memory usage: 48.8+ KB
In [4]Python
df.select_dtypes(include=["number"]).skew()
Out
N_Days           0.377727
Age              0.168027
Bilirubin        2.848223
Cholesterol      3.408526
Albumin         -0.582442
Copper           2.303640
Alk_Phos         2.992834
SGOT             1.449197
Tryglicerides    2.523902
Platelets        0.375918
Prothrombin      1.729987
Stage           -0.521648
dtype: float64
In [5]Python
df['Sex'] = df['Sex'].map({'F': 0, 'M': 1})


binary_cols = ['Ascites', 'Hepatomegaly', 'Spiders']

for col in binary_cols:
  df[col] = df[col].map({'N': 0, 'Y': 1})

df['Drug'] = df['Drug'].map({'Placebo': 0, 'D-penicillamine': 1})

skew_cols = ['Cholesterol', 'Copper', 'Tryglicerides']
for col in skew_cols:
  df[col] = df[col].fillna(df[col].median())
  df[col] = np.log1p(df[col])

df['Platelets'] = df['Platelets'].fillna(df['Platelets'].mean())
In [6]Python
df_no_supervisado = df.copy()
In [7]Python
df = pd.get_dummies(df, columns=['Edema', 'Stage'], dtype=int)
In [8]Python
df
Out
     N_Days Status  Drug    Age  Sex  Ascites  Hepatomegaly  Spiders  \
0       400      D     1  21464    0        1             1        1   
1      4500      C     1  20617    0        0             1        1   
2      1012      D     1  25594    1        0             0        0   
3      1925      D     1  19994    0        0             1        1   
4      1504     CL     0  13918    0        0             1        1   
..      ...    ...   ...    ...  ...      ...           ...      ...   
307    1153      C     1  22347    0        0             1        0   
308     994      C     0  21294    0        0             0        0   
309     939      C     1  22767    0        0             0        0   
310     839      C     1  13879    0        0             0        0   
311     788      C     0  12109    0        0             0        1   

     Bilirubin  Cholesterol  ...  Tryglicerides  Platelets  Prothrombin  \
0         14.5     5.568345  ...       5.153292      190.0         12.2   
1          1.1     5.713733  ...       4.488636      221.0         10.6   
2          1.4     5.176150  ...       4.025352      151.0         12.0   
3          1.8     5.501258  ...       4.532599      183.0         10.3   
4          3.4     5.634790  ...       4.290459      136.0         10.9   
..         ...          ...  ...            ...        ...          ...   
307        0.4     5.509388  ...       4.736198      288.0         10.4   
308        0.4     5.564520  ...       4.418841      231.0         10.8   
309        1.7     6.075346  ...       4.615121      234.0         10.2   
310        2.0     5.513429  ...       4.488636      335.0         10.5   
311        6.4     6.357842  ...       5.010635      200.0         10.8   

     Edema_N  Edema_S  Edema_Y  Stage_1.0  Stage_2.0  Stage_3.0  Stage_4.0  
0          0        0        1          0          0          0          1  
1          1        0        0          0          0          1          0  
2          0        1        0          0          0          0          1  
3          0        1        0          0          0          0          1  
4          1        0        0          0          0          1          0  
..       ...      ...      ...        ...        ...        ...        ...  
307        1        0        0          0          1          0          0  
308        1        0        0          0          1          0          0  
309        1        0        0          0          1          0          0  
310        1        0        0          0          1          0          0  
311        1        0        0          0          1          0          0  

[312 rows x 24 columns]
In [9]Python
df.info()
Out
<class 'pandas.core.frame.DataFrame'>
Index: 312 entries, 0 to 311
Data columns (total 24 columns):
 #   Column         Non-Null Count  Dtype  
---  ------         --------------  -----  
 0   N_Days         312 non-null    int64  
 1   Status         312 non-null    object 
 2   Drug           312 non-null    int64  
 3   Age            312 non-null    int64  
 4   Sex            312 non-null    int64  
 5   Ascites        312 non-null    int64  
 6   Hepatomegaly   312 non-null    int64  
 7   Spiders        312 non-null    int64  
 8   Bilirubin      312 non-null    float64
 9   Cholesterol    312 non-null    float64
 10  Albumin        312 non-null    float64
 11  Copper         312 non-null    float64
 12  Alk_Phos       312 non-null    float64
 13  SGOT           312 non-null    float64
 14  Tryglicerides  312 non-null    float64
 15  Platelets      312 non-null    float64
 16  Prothrombin    312 non-null    float64
 17  Edema_N        312 non-null    int64  
 18  Edema_S        312 non-null    int64  
 19  Edema_Y        312 non-null    int64  
 20  Stage_1.0      312 non-null    int64  
 21  Stage_2.0      312 non-null    int64  
 22  Stage_3.0      312 non-null    int64  
 23  Stage_4.0      312 non-null    int64  
dtypes: float64(9), int64(14), object(1)
memory usage: 60.9+ KB
In [10]Python
target_column = 'Status'
X = df.drop(columns=[target_column], errors='ignore')
y = df[target_column].map({'C': 0, 'CL': 1, 'D': 2})
In [11]Python
X
Out
     N_Days  Drug    Age  Sex  Ascites  Hepatomegaly  Spiders  Bilirubin  \
0       400     1  21464    0        1             1        1       14.5   
1      4500     1  20617    0        0             1        1        1.1   
2      1012     1  25594    1        0             0        0        1.4   
3      1925     1  19994    0        0             1        1        1.8   
4      1504     0  13918    0        0             1        1        3.4   
..      ...   ...    ...  ...      ...           ...      ...        ...   
307    1153     1  22347    0        0             1        0        0.4   
308     994     0  21294    0        0             0        0        0.4   
309     939     1  22767    0        0             0        0        1.7   
310     839     1  13879    0        0             0        0        2.0   
311     788     0  12109    0        0             0        1        6.4   

     Cholesterol  Albumin  ...  Tryglicerides  Platelets  Prothrombin  \
0       5.568345     2.60  ...       5.153292      190.0         12.2   
1       5.713733     4.14  ...       4.488636      221.0         10.6   
2       5.176150     3.48  ...       4.025352      151.0         12.0   
3       5.501258     2.54  ...       4.532599      183.0         10.3   
4       5.634790     3.53  ...       4.290459      136.0         10.9   
..           ...      ...  ...            ...        ...          ...   
307     5.509388     3.58  ...       4.736198      288.0         10.4   
308     5.564520     2.75  ...       4.418841      231.0         10.8   
309     6.075346     3.35  ...       4.615121      234.0         10.2   
310     5.513429     3.16  ...       4.488636      335.0         10.5   
311     6.357842     3.79  ...       5.010635      200.0         10.8   

     Edema_N  Edema_S  Edema_Y  Stage_1.0  Stage_2.0  Stage_3.0  Stage_4.0  
0          0        0        1          0          0          0          1  
1          1        0        0          0          0          1          0  
2          0        1        0          0          0          0          1  
3          0        1        0          0          0          0          1  
4          1        0        0          0          0          1          0  
..       ...      ...      ...        ...        ...        ...        ...  
307        1        0        0          0          1          0          0  
308        1        0        0          0          1          0          0  
309        1        0        0          0          1          0          0  
310        1        0        0          0          1          0          0  
311        1        0        0          0          1          0          0  

[312 rows x 23 columns]
In [12]Python
encoder = LabelEncoder()
y_encoded = encoder.fit_transform(y)
In [13]Python
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
In [14]Python
X_scaled_train, X_scaled_test, y_scaled_train, y_scaled_test = train_test_split(X_scaled, y_encoded, test_size=0.3, random_state=42)
In [15]Python
smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X, y)
In [16]Python
X_res_train, X_res_test, y_res_train, y_res_test = train_test_split(X_resampled, y_resampled, test_size=0.3, random_state=42, stratify=y_resampled)
In [17]Python
models = {
    "Logistic Regression": LogisticRegression(max_iter=1000, random_state=42, solver='saga', class_weight='balanced'),
    "Random Forest": RandomForestClassifier(random_state=42, class_weight='balanced'),
    "Decision Tree": DecisionTreeClassifier(random_state=42, class_weight='balanced'),
    "GradientBoosting": GradientBoostingClassifier(n_estimators=100, random_state=42),
    "Support Vector Machine": SVC(random_state=42, class_weight='balanced')
}
In [18]Python
def evaluate_model(models, X_train, y_train, X_test, y_test):
    model_comparisons = []
    for model_name, model in models.items():
        model.fit(X_train, y_train)
        y_pred = model.predict(X_test)

        report = classification_report(y_test, y_pred, target_names=['C', 'D', 'CL'], output_dict=True)
        accuracy = accuracy_score(y_test, y_pred)

        model_comparisons.append({
            "Model": model_name,
            "Accuracy": accuracy,
            "Precision (Macro Avg)": report["macro avg"]["precision"],
            "Recall (Macro Avg)": report["macro avg"]["recall"],
            "F1-Score (Macro Avg)": report["macro avg"]["f1-score"],
        })

    return pd.DataFrame(model_comparisons)
In [19]Python
resampled_df = evaluate_model(models, X_res_train, y_res_train, X_res_test, y_res_test )
resampled_df
Out
                    Model  Accuracy  Precision (Macro Avg)  \
0     Logistic Regression  0.565789               0.565717   
1           Random Forest  0.828947               0.829173   
2           Decision Tree  0.664474               0.660087   
3        GradientBoosting  0.776316               0.774934   
4  Support Vector Machine  0.578947               0.579060   

   Recall (Macro Avg)  F1-Score (Macro Avg)  
0            0.565359              0.565385  
1            0.828758              0.828758  
2            0.663529              0.661517  
3            0.775817              0.775174  
4            0.577124              0.552689  
In [20]Python
resampled_df.set_index("Model").plot(kind="bar", figsize=(10, 6), rot=0)
plt.title("Comparación de Modelos, Datos Balanceados")
plt.ylabel("Valor")
plt.legend(loc="best")
plt.grid(axis="y")
plt.show()
Out
Output gráfico de la celda 20
In [21]Python
#Mostrar matrices de confusion para resampled_df
fig, axes = plt.subplots(3, 2, figsize=(12, 18))
axes = axes.flatten()

for i, (name, model) in enumerate(models.items()):
    model.fit(X_res_train, y_res_train)
    y_pred = model.predict(X_res_test)
    cm = confusion_matrix(y_res_test, y_pred)

    sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', ax=axes[i])
    axes[i].set_title(name)
    axes[i].set_xlabel('Prediccion')
    axes[i].set_ylabel('Actual')

# Título general para la figura
fig.suptitle("Matrices de confusion para Datos Balanceados", fontsize=16)

# Ocultar el sexto subplot innecesario
for j in range(len(models), len(axes)):
    fig.delaxes(axes[j])

plt.tight_layout()
plt.show()
Out
Output gráfico de la celda 21
In [22]Python
scaled_df = evaluate_model(models, X_scaled_train, y_scaled_train, X_scaled_test, y_scaled_test)
scaled_df
Out
                    Model  Accuracy  Precision (Macro Avg)  \
0     Logistic Regression  0.670213               0.598162   
1           Random Forest  0.702128               0.477650   
2           Decision Tree  0.563830               0.389556   
3        GradientBoosting  0.659574               0.440171   
4  Support Vector Machine  0.702128               0.611111   

   Recall (Macro Avg)  F1-Score (Macro Avg)  
0            0.600908              0.597787  
1            0.522216              0.493249  
2            0.419172              0.401093  
3            0.491208              0.463496  
4            0.598960              0.601773  
In [23]Python
scaled_df.set_index("Model").plot(kind="bar", figsize=(10, 6), rot=0)
plt.title("Comparación de Modelos, Datos Escalados")
plt.ylabel("Valor")
plt.legend(loc="best")
plt.grid(axis="y")
plt.tight_layout()
plt.show()
Out
Output gráfico de la celda 23
In [24]Python
#Mostrar matrices de confusion para Scaled_df
fig, axes = plt.subplots(3, 2, figsize=(12, 18))
axes = axes.flatten()

for i, (name, model) in enumerate(models.items()):
    model.fit(X_scaled_train, y_scaled_train)
    y_pred = model.predict(X_scaled_test)
    cm = confusion_matrix(y_scaled_test, y_pred)

    sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', ax=axes[i])
    axes[i].set_title(name)
    axes[i].set_xlabel('Prediccion')
    axes[i].set_ylabel('Actual')

fig.suptitle("Matrices de confusion para Datos Escalados", fontsize=16)

# Ocultar el sexto subplot innecesario
for j in range(len(models), len(axes)):
    fig.delaxes(axes[j])

plt.tight_layout()
plt.show()
Out
Output gráfico de la celda 24

Sección: Análisis No Supervisado

In [25]Python
df=df_no_supervisado
In [26]Python
df.Status = df.Status.replace({"C": 0, "CL": 1,"D":2})
df.Edema=df.Edema.replace({"N":0,"S":1,"Y":2})

Analisando las variables categoricas

In [27]Python
d_categorica=df[['Drug','Sex','Ascites','Hepatomegaly','Spiders','Edema','Status']]
sns.pairplot(d_categorica, hue='Status', palette='Set1')

# Mostrar el gráfico
plt.show()
Out
Output gráfico de la celda 27

Observamos la correlación de las variables categoricas con el status

In [28]Python
d_categorica.corr()
Out
                  Drug       Sex   Ascites  Hepatomegaly   Spiders     Edema  \
Drug          1.000000  0.055567  0.044415     -0.102935 -0.008164  0.012370   
Sex           0.055567  1.000000  0.008688      0.050949 -0.141379  0.037309   
Ascites       0.044415  0.008688  1.000000      0.161045  0.161339  0.585731   
Hepatomegaly -0.102935  0.050949  0.161045      1.000000  0.295054  0.170979   
Spiders      -0.008164 -0.141379  0.161339      0.295054  1.000000  0.272282   
Edema         0.012370  0.037309  0.585731      0.170979  0.272282  1.000000   
Status        0.025234  0.166936  0.317345      0.334591  0.231614  0.320095   

                Status  
Drug          0.025234  
Sex           0.166936  
Ascites       0.317345  
Hepatomegaly  0.334591  
Spiders       0.231614  
Edema         0.320095  
Status        1.000000  

Generamos el grafico con las variables categoricas que se decidieron ocupar

In [29]Python
d_categorica2=df[['Ascites','Edema','Status']]
sns.pairplot(d_categorica2, hue='Status', palette='Set1')

# Mostrar el gráfico
plt.show()
Out
Output gráfico de la celda 29

Analisis de todas las variables numericas

In [30]Python
d_numerica=df[['Age','Bilirubin','Cholesterol','Albumin','Copper','Alk_Phos','SGOT','Tryglicerides','Platelets','Prothrombin','Status']]
In [31]Python
sns.pairplot(d_numerica, hue='Status',palette='Set1')

# Mostrar el gráfico
plt.show()
Out
Output gráfico de la celda 31

hacemos la tabla de correlación para variables numericas respecto a status

In [32]Python
d_numerica.corr()
Out
                    Age  Bilirubin  Cholesterol   Albumin    Copper  Alk_Phos  \
Age            1.000000   0.038601    -0.166727 -0.195264  0.005009 -0.047247   
Bilirubin      0.038601   1.000000     0.357602 -0.334638  0.450936  0.116984   
Cholesterol   -0.166727   0.357602     1.000000 -0.033325  0.211246  0.175835   
Albumin       -0.195264  -0.334638    -0.033325  1.000000 -0.298378 -0.101456   
Copper         0.005009   0.450936     0.211246 -0.298378  1.000000  0.232340   
Alk_Phos      -0.047247   0.116984     0.175835 -0.101456  0.232340  1.000000   
SGOT          -0.149869   0.441730     0.356169 -0.220047  0.337426  0.112217   
Tryglicerides  0.030843   0.390547     0.363428 -0.098887  0.296288  0.196786   
Platelets     -0.138371  -0.086808     0.222309  0.202989 -0.087908  0.142792   
Prothrombin    0.196300   0.361742    -0.105664 -0.234013  0.182098  0.089384   
Status         0.201685   0.436755     0.181559 -0.310052  0.420547  0.225822   

                   SGOT  Tryglicerides  Platelets  Prothrombin    Status  
Age           -0.149869       0.030843  -0.138371     0.196300  0.201685  
Bilirubin      0.441730       0.390547  -0.086808     0.361742  0.436755  
Cholesterol    0.356169       0.363428   0.222309    -0.105664  0.181559  
Albumin       -0.220047      -0.098887   0.202989    -0.234013 -0.310052  
Copper         0.337426       0.296288  -0.087908     0.182098  0.420547  
Alk_Phos       0.112217       0.196786   0.142792     0.089384  0.225822  
SGOT           1.000000       0.133198  -0.119533     0.112174  0.294376  
Tryglicerides  0.133198       1.000000   0.082330    -0.024454  0.193943  
Platelets     -0.119533       0.082330   1.000000    -0.221270 -0.148279  
Prothrombin    0.112174      -0.024454  -0.221270     1.000000  0.405888  
Status         0.294376       0.193943  -0.148279     0.405888  1.000000  

Observando las graficas y la correlaciones en las que mejor se observa la segmentación son Bilirubin, Albumin,Prothrombin aparte de tener una buena correlación con Status

Generamos la imagen con las variables numericas a considerar

In [33]Python
d_numerica2=df[['Bilirubin','Albumin','Prothrombin','Status']]
sns.pairplot(d_numerica2, hue='Status',palette='Set1')

# Mostrar el gráfico
plt.show()
Out
Output gráfico de la celda 33
In [34]Python
pip install kmodes
Out
Requirement already satisfied: kmodes in /usr/local/lib/python3.11/dist-packages (0.12.2)
Requirement already satisfied: numpy>=1.10.4 in /usr/local/lib/python3.11/dist-packages (from kmodes) (1.26.4)
Requirement already satisfied: scikit-learn>=0.22.0 in /usr/local/lib/python3.11/dist-packages (from kmodes) (1.6.1)
Requirement already satisfied: scipy>=0.13.3 in /usr/local/lib/python3.11/dist-packages (from kmodes) (1.13.1)
Requirement already satisfied: joblib>=0.11 in /usr/local/lib/python3.11/dist-packages (from kmodes) (1.4.2)
Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=0.22.0->kmodes) (3.5.0)
In [35]Python
df2=df[['Ascites','Edema','Prothrombin', 'Albumin', 'Bilirubin','Status']]
In [36]Python
categorical_columns = ['Ascites','Edema']

num_cols = ['Prothrombin', 'Albumin', 'Bilirubin']
cat_cols = categorical_columns

Metodo del codo para variables no escaladas

In [37]Python
sse = []
# Iterar sobre diferentes números de clústeres
for k in range(1, 11):  # Probar de 1 a 10 clústeres
    kproto = KPrototypes(n_clusters=k, init='Cao', verbose=0)
    kproto.fit(df[num_cols + cat_cols], categorical=[df2.columns.get_loc(c) for c in cat_cols])
    sse.append(kproto.cost_)

# Graficar el método del codo
plt.plot(range(1, 11), sse, marker='o')
plt.title('Método del Codo para determinar el número de Clústeres')
plt.xlabel('Número de Clústeres')
plt.ylabel('SSE (Suma de Errores Cuadráticos)')
plt.show()
Out
Output gráfico de la celda 37

Grafico de cluster con variables no escaladas

In [38]Python
semilla=42
kproto = KPrototypes(n_clusters=3, init='Cao', verbose=2,random_state=semilla)


clusters = kproto.fit_predict(df2[num_cols + cat_cols], categorical=[df2.columns.get_loc(c) for c in cat_cols])


df2['Cluster'] = clusters


pca = PCA(n_components=2,random_state=semilla)
pca_result = pca.fit_transform(df2[num_cols + cat_cols])

df_pca = pd.DataFrame(pca_result, columns=['PCA1', 'PCA2'])


df_pca['Cluster'] = df2['Cluster']
df_pca['Status'] = df2['Status']



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

# Graficar los puntos, coloreados según el 'Status'
sns.scatterplot(x='PCA1', y='PCA2', hue='Cluster', style='Status', palette='Set1', data=df_pca, s=100, edgecolor='k', alpha=0.7)


plt.title('Visualización de Clústeres en 2D con Diferenciación por Cluster y Status', fontsize=16)
plt.xlabel('Componente Principal 1', fontsize=14)
plt.ylabel('Componente Principal 2', fontsize=14)


plt.legend(title='Cluster / Status')
plt.show()
Out
Initialization method and algorithm are deterministic. Setting n_init to 1.
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 1, iteration: 1/100, moves: 73, ncost: 1631.289752054302
Run: 1, iteration: 2/100, moves: 40, ncost: 1437.399063380516
Run: 1, iteration: 3/100, moves: 12, ncost: 1422.1999047018464
Run: 1, iteration: 4/100, moves: 9, ncost: 1401.8776603426713
Run: 1, iteration: 5/100, moves: 13, ncost: 1376.7781399550288
Run: 1, iteration: 6/100, moves: 4, ncost: 1375.0971995794391
Run: 1, iteration: 7/100, moves: 0, ncost: 1375.0971995794391
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 2, iteration: 1/100, moves: 32, ncost: 1376.7983701797104
Run: 2, iteration: 2/100, moves: 5, ncost: 1372.7251376295148
Run: 2, iteration: 3/100, moves: 0, ncost: 1372.7251376295148
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 3, iteration: 1/100, moves: 69, ncost: 2059.966613976496
Run: 3, iteration: 2/100, moves: 45, ncost: 1438.3393092756087
Run: 3, iteration: 3/100, moves: 13, ncost: 1422.1999047018473
Run: 3, iteration: 4/100, moves: 9, ncost: 1401.8776603426718
Run: 3, iteration: 5/100, moves: 13, ncost: 1376.7781399550288
Run: 3, iteration: 6/100, moves: 4, ncost: 1375.0971995794391
Run: 3, iteration: 7/100, moves: 0, ncost: 1375.0971995794391
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 4, iteration: 1/100, moves: 33, ncost: 1443.8719076671237
Run: 4, iteration: 2/100, moves: 11, ncost: 1427.689116213647
Run: 4, iteration: 3/100, moves: 7, ncost: 1417.1195658172214
Run: 4, iteration: 4/100, moves: 8, ncost: 1397.7789770488191
Run: 4, iteration: 5/100, moves: 11, ncost: 1376.7781399550286
Run: 4, iteration: 6/100, moves: 4, ncost: 1375.0971995794391
Run: 4, iteration: 7/100, moves: 0, ncost: 1375.0971995794391
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 5, iteration: 1/100, moves: 34, ncost: 1449.8108667429874
Run: 5, iteration: 2/100, moves: 9, ncost: 1427.6891162136471
Run: 5, iteration: 3/100, moves: 7, ncost: 1417.1195658172214
Run: 5, iteration: 4/100, moves: 8, ncost: 1397.7789770488196
Run: 5, iteration: 5/100, moves: 11, ncost: 1376.7781399550288
Run: 5, iteration: 6/100, moves: 4, ncost: 1375.0971995794391
Run: 5, iteration: 7/100, moves: 0, ncost: 1375.0971995794391
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 6, iteration: 1/100, moves: 9, ncost: 1434.5889524272511
Run: 6, iteration: 2/100, moves: 9, ncost: 1422.1999047018462
Run: 6, iteration: 3/100, moves: 9, ncost: 1401.8776603426713
Run: 6, iteration: 4/100, moves: 13, ncost: 1376.7781399550286
Run: 6, iteration: 5/100, moves: 4, ncost: 1375.0971995794391
Run: 6, iteration: 6/100, moves: 0, ncost: 1375.0971995794391
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 7, iteration: 1/100, moves: 15, ncost: 1434.5889524272511
Run: 7, iteration: 2/100, moves: 9, ncost: 1422.1999047018467
Run: 7, iteration: 3/100, moves: 9, ncost: 1401.8776603426713
Run: 7, iteration: 4/100, moves: 13, ncost: 1376.7781399550286
Run: 7, iteration: 5/100, moves: 4, ncost: 1375.0971995794391
Run: 7, iteration: 6/100, moves: 0, ncost: 1375.0971995794391
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 8, iteration: 1/100, moves: 166, ncost: 1815.0372870425456
Run: 8, iteration: 2/100, moves: 58, ncos
… (output truncado)
Output gráfico de la celda 38

Analisis de cada cluster

In [39]Python
import matplotlib.pyplot as plt
import seaborn as sns

# Definir los clústeres únicos
clusters_unique = df_pca['Cluster'].unique()

# Crear gráficos por separado para cada clúster
for cluster in clusters_unique:
    # Filtrar los datos para el clúster actual
    df_cluster = df_pca[df_pca['Cluster'] == cluster]

    # Crear el gráfico para este clúster
    plt.figure(figsize=(10, 6))

    # Graficar los puntos de este clúster, coloreados por 'Status'
    sns.scatterplot(x='PCA1', y='PCA2', hue='Status', style='Status',
                    palette='Set1', data=df_cluster, s=100, edgecolor='k', alpha=0.7)

    # Título y etiquetas
    plt.title(f'Visualización del Clúster {cluster} en 2D con Diferenciación por Status', fontsize=16)
    plt.xlabel('Componente Principal 1', fontsize=14)
    plt.ylabel('Componente Principal 2', fontsize=14)

    # Mostrar el gráfico
    plt.legend(title='Status')
    plt.show()
Out
Output gráfico de la celda 39Output gráfico de la celda 39Output gráfico de la celda 39

Revisión de las componentes principales

In [40]Python
components_df = pd.DataFrame(pca.components_, columns=num_cols + cat_cols)

# Mostrar el DataFrame de componentes
print("\nDataFrame de componentes de PCA (cargas de cada variable por componente):")
print(components_df)
Out
DataFrame de componentes de PCA (cargas de cada variable por componente):
   Prothrombin   Albumin  Bilirubin   Ascites     Edema
0     0.083740 -0.031454   0.994474  0.022626  0.050068
1     0.967923 -0.077699  -0.096003  0.072216  0.206535

Obsevamos que para la componente principal 1 la influlle en gran manera la bilirrubina

Hacemos el analis escalando la data

Metodo del codo para variables escaladas

In [41]Python
df3=df2
scaler = StandardScaler()
df3[num_cols] = scaler.fit_transform(df3[num_cols])
sse = []
# Iterar sobre diferentes números de clústeres
for k in range(1, 11):  # Probar de 1 a 10 clústeres
    kproto = KPrototypes(n_clusters=k, init='Cao', verbose=0)
    kproto.fit(df[num_cols + cat_cols], categorical=[df2.columns.get_loc(c) for c in cat_cols])
    sse.append(kproto.cost_)

# Graficar el método del codo
plt.plot(range(1, 11), sse, marker='o')
plt.title('Método del Codo para determinar el número de Clústeres')
plt.xlabel('Número de Clústeres')
plt.ylabel('SSE (Suma de Errores Cuadráticos)')
plt.show()
Out
Output gráfico de la celda 41

Cluster con variables escaladas

In [42]Python
# Inicializar el modelo K-Prototypes
semilla=42
kproto = KPrototypes(n_clusters=3, init='Cao', verbose=2,random_state=semilla)

# Aplicar el algoritmo K-prototypes
clusters = kproto.fit_predict(df3[num_cols + cat_cols], categorical=[df3.columns.get_loc(c) for c in cat_cols])

# Añadir los clústeres al DataFrame
df3['Cluster'] = clusters

# Usamos PCA para reducir la dimensionalidad a 2 dimensiones
pca3 = PCA(n_components=2,random_state=semilla)
pca_result3 = pca3.fit_transform(df3[num_cols + cat_cols])

# Crear un DataFrame para los resultados de PCA
df_pca3 = pd.DataFrame(pca_result3, columns=['PCA1', 'PCA2'])

# Añadir las columnas de 'Cluster' y 'Estado' (Status) al DataFrame de PCA
df_pca3['Cluster'] = df3['Cluster']
df_pca3['Status'] = df3['Status']  # Usamos la columna 'Estado' como 'Status'

# Visualizar los clústeres en 2D, diferenciando por 'Status'
plt.figure(figsize=(10, 6))

# Graficar los puntos, coloreados según el 'Status'
sns.scatterplot(x='PCA1', y='PCA2', hue='Cluster', style='Status', palette='Set1', data=df_pca3, s=100, edgecolor='k', alpha=0.7)

# Título y etiquetas
plt.title('Visualización de Clústeres en 2D con Diferenciación por Cluster y Status', fontsize=16)
plt.xlabel('Componente Principal 1', fontsize=14)
plt.ylabel('Componente Principal 2', fontsize=14)

# Mostrar el gráfico
plt.legend(title='Cluster / Status')
plt.show()
Out
Initialization method and algorithm are deterministic. Setting n_init to 1.
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 1, iteration: 1/100, moves: 49, ncost: 309.74976279910476
Run: 1, iteration: 2/100, moves: 16, ncost: 296.75117438533
Run: 1, iteration: 3/100, moves: 0, ncost: 296.75117438533
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 2, iteration: 1/100, moves: 19, ncost: 310.5903623619835
Run: 2, iteration: 2/100, moves: 12, ncost: 306.4316137319709
Run: 2, iteration: 3/100, moves: 7, ncost: 305.8106733263316
Run: 2, iteration: 4/100, moves: 4, ncost: 304.56660069642476
Run: 2, iteration: 5/100, moves: 5, ncost: 302.3042799844034
Run: 2, iteration: 6/100, moves: 7, ncost: 300.9220806489928
Run: 2, iteration: 7/100, moves: 1, ncost: 300.9027320019633
Run: 2, iteration: 8/100, moves: 0, ncost: 300.9027320019633
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 3, iteration: 1/100, moves: 162, ncost: 348.9891425759518
Run: 3, iteration: 2/100, moves: 50, ncost: 302.7205981079066
Run: 3, iteration: 3/100, moves: 7, ncost: 296.75117438533
Run: 3, iteration: 4/100, moves: 0, ncost: 296.75117438533
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 4, iteration: 1/100, moves: 67, ncost: 305.2424834163384
Run: 4, iteration: 2/100, moves: 12, ncost: 301.1685336772529
Run: 4, iteration: 3/100, moves: 2, ncost: 301.08757315650416
Run: 4, iteration: 4/100, moves: 0, ncost: 301.08757315650416
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 5, iteration: 1/100, moves: 67, ncost: 339.6704770504796
Run: 5, iteration: 2/100, moves: 52, ncost: 316.52236002231655
Run: 5, iteration: 3/100, moves: 27, ncost: 309.15018189821876
Run: 5, iteration: 4/100, moves: 26, ncost: 304.320736113516
Run: 5, iteration: 5/100, moves: 19, ncost: 300.95929265549205
Run: 5, iteration: 6/100, moves: 3, ncost: 300.9107993657127
Run: 5, iteration: 7/100, moves: 0, ncost: 300.9107993657127
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 6, iteration: 1/100, moves: 7, ncost: 296.75117438533005
Run: 6, iteration: 2/100, moves: 0, ncost: 296.75117438533005
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 7, iteration: 1/100, moves: 8, ncost: 296.75117438533005
Run: 7, iteration: 2/100, moves: 0, ncost: 296.75117438533005
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 8, iteration: 1/100, moves: 55, ncost: 309.91601780432455
Run: 8, iteration: 2/100, moves: 20, ncost: 296.75117438533
Run: 8, iteration: 3/100, moves: 0, ncost: 296.75117438533
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 9, iteration: 1/100, moves: 16, ncost: 296.93398502841603
Run: 9, iteration: 2/100, moves: 1, ncost: 296.75117438533005
Run: 9, iteration: 3/100, moves: 0, ncost: 296.75117438533005
Init: initializing centroids
Init: initializing clusters
Starting iterations...
Run: 10, iteration: 1/100, moves: 105, ncost: 323.27485902198
Run: 10, iteration: 2/100, moves: 46, ncost: 307.34683894341464
Run: 10, iteration: 3/100, moves: 31, ncost: 301.9365841369607
Run: 10, iteration: 4/100, moves: 12, ncost: 301.122673393078
Run: 10, iteration: 5/100, moves: 2, ncost: 301.08757315650416
Run: 10, iteration: 6/100, moves: 0, ncost: 301.08757315650416
Best run was number 1
Output gráfico de la celda 42

Analisis de cada cluster

In [43]Python
import matplotlib.pyplot as plt
import seaborn as sns

# Definir los clústeres únicos
clusters_unique = df_pca3['Cluster'].unique()

# Crear gráficos por separado para cada clúster
for cluster in clusters_unique:
    # Filtrar los datos para el clúster actual
    df_cluster = df_pca3[df_pca3['Cluster'] == cluster]

    # Crear el gráfico para este clúster
    plt.figure(figsize=(10, 6))

    # Graficar los puntos de este clúster, coloreados por 'Status'
    sns.scatterplot(x='PCA1', y='PCA2', hue='Status', style='Status',
                    palette='Set1', data=df_cluster, s=100, edgecolor='k', alpha=0.7)

    # Título y etiquetas
    plt.title(f'Visualización del Clúster {cluster} en 2D con Diferenciación por Status', fontsize=16)
    plt.xlabel('Componente Principal 1', fontsize=14)
    plt.ylabel('Componente Principal 2', fontsize=14)

    # Mostrar el gráfico
    plt.legend(title='Status')
    plt.show()
Out
Output gráfico de la celda 43Output gráfico de la celda 43Output gráfico de la celda 43

Analisis componentes principales

In [44]Python
components_df = pd.DataFrame(pca3.components_, columns=num_cols + cat_cols)

# Mostrar el DataFrame de componentes
print("\nDataFrame de componentes de PCA (cargas de cada variable por componente):")
print(components_df)
Out
DataFrame de componentes de PCA (cargas de cada variable por componente):
   Prothrombin   Albumin  Bilirubin   Ascites    Edema
0     0.540619 -0.527940   0.592097  0.109177  0.25790
1     0.659744  0.747131   0.075703 -0.021758 -0.01814

la componente que permite segmentar los cluster es la PCA1 la cual la afecta la Protrombina, Bilirrubina y los edemas en menor escala

← Volver al casoComentar este trabajo