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.
data.info()<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
max_nans_allowed = 3
df = data.dropna(thresh=data.shape[1] - max_nans_allowed)
df = df.drop(columns=['ID'])df.info()<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
df.select_dtypes(include=["number"]).skew()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
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())df_no_supervisado = df.copy()df = pd.get_dummies(df, columns=['Edema', 'Stage'], dtype=int)df 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]df.info()<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
target_column = 'Status'
X = df.drop(columns=[target_column], errors='ignore')
y = df[target_column].map({'C': 0, 'CL': 1, 'D': 2})X 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]encoder = LabelEncoder()
y_encoded = encoder.fit_transform(y)scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)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)smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X, y)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)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')
}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)resampled_df = evaluate_model(models, X_res_train, y_res_train, X_res_test, y_res_test )
resampled_dfModel 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
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()#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()scaled_df = evaluate_model(models, X_scaled_train, y_scaled_train, X_scaled_test, y_scaled_test)
scaled_dfModel 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
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()#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()Sección: Análisis No Supervisado
df=df_no_supervisadodf.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
d_categorica=df[['Drug','Sex','Ascites','Hepatomegaly','Spiders','Edema','Status']]
sns.pairplot(d_categorica, hue='Status', palette='Set1')
# Mostrar el gráfico
plt.show()Observamos la correlación de las variables categoricas con el status
d_categorica.corr() 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
d_categorica2=df[['Ascites','Edema','Status']]
sns.pairplot(d_categorica2, hue='Status', palette='Set1')
# Mostrar el gráfico
plt.show()Analisis de todas las variables numericas
d_numerica=df[['Age','Bilirubin','Cholesterol','Albumin','Copper','Alk_Phos','SGOT','Tryglicerides','Platelets','Prothrombin','Status']]sns.pairplot(d_numerica, hue='Status',palette='Set1')
# Mostrar el gráfico
plt.show()hacemos la tabla de correlación para variables numericas respecto a status
d_numerica.corr() 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
d_numerica2=df[['Bilirubin','Albumin','Prothrombin','Status']]
sns.pairplot(d_numerica2, hue='Status',palette='Set1')
# Mostrar el gráfico
plt.show()pip install kmodesRequirement 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)
df2=df[['Ascites','Edema','Prothrombin', 'Albumin', 'Bilirubin','Status']]categorical_columns = ['Ascites','Edema']
num_cols = ['Prothrombin', 'Albumin', 'Bilirubin']
cat_cols = categorical_columnsMetodo del codo para variables no escaladas
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()Grafico de cluster con variables no escaladas
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()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)
Analisis de cada cluster
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()Revisión de las componentes principales
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)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
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()Cluster con variables escaladas
# 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()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
Analisis de cada cluster
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()Analisis componentes principales
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)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