Esta es una demostración de cómo se hace un EDA (Análisis exploratorio de datos) a datos medicos

  1. Carga de datos
In [ ]:
import pandas as pd
    
    # Assuming your CSV file is named 'your_file.csv'
    # Replace 'your_file.csv' with the actual name of your file
    try:
      df = pd.read_csv('Medicaldataset.csv',sep=";")
      print("Primeras filas del DataFrame:")
      print(df.head())
      print("\nInformación general del DataFrame:")
      df.info()
    except FileNotFoundError:
      print("Error: 'your_file.csv' no encontrado. Asegúrate de que el archivo CSV está en el directorio correcto.")
    except Exception as e:
      print(f"Ocurrió un error al leer el archivo CSV: {e}")
    
Primeras filas del DataFrame:
       Age  Gender  Heart rate  Systolic blood pressure  Diastolic blood pressure  \
    0   64       1          66                      160                        83   
    1   21       1          94                       98                        46   
    2   55       1          64                      160                        77   
    3   64       1          70                      120                        55   
    4   55       1          64                      112                        65   
    
       Blood sugar  CK-MB  Troponin    Result  
    0        160.0   1.80     0.012  negative  
    1        296.0   6.75     1.060  positive  
    2        270.0   1.99     0.003  negative  
    3        270.0  13.87     0.122  positive  
    4        300.0   1.08     0.003  negative  
    
    Información general del DataFrame:
    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 1319 entries, 0 to 1318
    Data columns (total 9 columns):
     #   Column                    Non-Null Count  Dtype  
    ---  ------                    --------------  -----  
     0   Age                       1319 non-null   int64  
     1   Gender                    1319 non-null   int64  
     2   Heart rate                1319 non-null   int64  
     3   Systolic blood pressure   1319 non-null   int64  
     4   Diastolic blood pressure  1319 non-null   int64  
     5   Blood sugar               1319 non-null   float64
     6   CK-MB                     1319 non-null   float64
     7   Troponin                  1319 non-null   float64
     8   Result                    1319 non-null   object 
    dtypes: float64(3), int64(5), object(1)
    memory usage: 92.9+ KB
    

Se observa las dimensiones de la data

In [ ]:
print(f"\nEl DataFrame tiene {df.shape[0]} filas.")
    
    El DataFrame tiene 1319 filas.
    
In [3]:
df.head()
    
Out[3]:
Age Gender Heart rate Systolic blood pressure Diastolic blood pressure Blood sugar CK-MB Troponin Result
0 64 1 66 160 83 160.0 1.80 0.012 negative
1 21 1 94 98 46 296.0 6.75 1.060 positive
2 55 1 64 160 77 270.0 1.99 0.003 negative
3 64 1 70 120 55 270.0 13.87 0.122 positive
4 55 1 64 112 65 300.0 1.08 0.003 negative
In [ ]:
# Eliminar las columnas "CK-MB" y "Systolic blood pressure"
    columns_to_drop = ["CK-MB", "Systolic blood pressure"]
    df = df.drop(columns=columns_to_drop, errors='ignore')
    
    print("\nDataFrame después de eliminar columnas:")
    print(df.head())
    
    DataFrame después de eliminar columnas:
       Age  Gender  Heart rate  Diastolic blood pressure  Blood sugar  Troponin  \
    0   64       1          66                        83        160.0     0.012   
    1   21       1          94                        46        296.0     1.060   
    2   55       1          64                        77        270.0     0.003   
    3   64       1          70                        55        270.0     0.122   
    4   55       1          64                        65        300.0     0.003   
    
         Result  
    0  negative  
    1  positive  
    2  negative  
    3  positive  
    4  negative  
    
In [ ]:
# Permíteme definir algunas que son categóricas pero que están en el dataset como numéricas nominales
    
    # Lista de variables que son categóricas pero están representadas como numéricas
    categorical_numerical_vars = ['Gender'] # Agrega aquí los nombres de tus variables
    
    # Separar las columnas en listas de variables numéricas y categóricas
    numeric_cols = df.select_dtypes(include=['int64', 'float64']).columns.tolist()
    categorical_cols = df.select_dtypes(include=['object', 'category']).columns.tolist()
    
    # Mover las variables especificadas de la lista numérica a la categórica si existen en la lista numérica
    for var in categorical_numerical_vars:
        if var in numeric_cols:
            numeric_cols.remove(var)
            categorical_cols.append(var)
    
    print("Variables numéricas:", numeric_cols)
    print("Variables categóricas:", categorical_cols)
    
Variables numéricas: ['Age', 'Heart rate', 'Diastolic blood pressure', 'Blood sugar', 'Troponin']
    Variables categóricas: ['Result', 'Gender']
    
In [ ]:
# Verificar si hay valores nulos por columna
    print("Número de valores nulos por columna antes de la eliminación:")
    print(df.isnull().sum())
    
    # Eliminar filas con cualquier valor nulo
    df.dropna(inplace=True)
    
    print("\nDataFrame después de eliminar filas con valores nulos:")
    print(df.head())
    
    print("\nNúmero de valores nulos por columna después de la eliminación:")
    print(df.isnull().sum())
    
Número de valores nulos por columna antes de la eliminación:
    Age                         0
    Gender                      0
    Heart rate                  0
    Diastolic blood pressure    0
    Blood sugar                 0
    Troponin                    0
    Result                      0
    dtype: int64
    
    DataFrame después de eliminar filas con valores nulos:
       Age  Gender  Heart rate  Diastolic blood pressure  Blood sugar  Troponin  \
    0   64       1          66                        83        160.0     0.012   
    1   21       1          94                        46        296.0     1.060   
    2   55       1          64                        77        270.0     0.003   
    3   64       1          70                        55        270.0     0.122   
    4   55       1          64                        65        300.0     0.003   
    
         Result  
    0  negative  
    1  positive  
    2  negative  
    3  positive  
    4  negative  
    
    Número de valores nulos por columna después de la eliminación:
    Age                         0
    Gender                      0
    Heart rate                  0
    Diastolic blood pressure    0
    Blood sugar                 0
    Troponin                    0
    Result                      0
    dtype: int64
    

Label econder se usa para convertir la variable que queremos predecir o trabajar a 0 y 1

In [ ]:
from sklearn.preprocessing import LabelEncoder
    
    # Inicializar LabelEncoder
    label_encoder = LabelEncoder()
    
    # Aplicar LabelEncoder a cada columna categórica
    for col in categorical_cols:
        df[col] = label_encoder.fit_transform(df[col])
    
    print("\nDataFrame después de la codificación con LabelEncoder:")
    print(df.head())
    
    # Verificar los tipos de datos después de la codificación
    print("\nTipos de datos después de la codificación:")
    df.dtypes
    
    DataFrame después de la codificación con LabelEncoder:
       Age  Gender  Heart rate  Diastolic blood pressure  Blood sugar  Troponin  \
    0   64       1          66                        83        160.0     0.012   
    1   21       1          94                        46        296.0     1.060   
    2   55       1          64                        77        270.0     0.003   
    3   64       1          70                        55        270.0     0.122   
    4   55       1          64                        65        300.0     0.003   
    
       Result  
    0       0  
    1       1  
    2       0  
    3       1  
    4       0  
    
    Tipos de datos después de la codificación:
    
Out[ ]:
0
Age int64
Gender int64
Heart rate int64
Diastolic blood pressure int64
Blood sugar float64
Troponin float64
Result int64

In [8]:
df.describe()
    
Out[8]:
Age Gender Heart rate Diastolic blood pressure Blood sugar Troponin Result
count 1319.000000 1319.000000 1319.000000 1319.000000 1319.000000 1319.000000 1319.000000
mean 56.191812 0.659591 78.336619 72.269143 146.634344 0.360942 0.614102
std 13.647315 0.474027 51.630270 14.033924 74.923045 1.154568 0.486991
min 14.000000 0.000000 20.000000 38.000000 35.000000 0.001000 0.000000
25% 47.000000 0.000000 64.000000 62.000000 98.000000 0.006000 0.000000
50% 58.000000 1.000000 74.000000 72.000000 116.000000 0.014000 1.000000
75% 65.000000 1.000000 85.000000 81.000000 169.500000 0.085500 1.000000
max 103.000000 1.000000 1111.000000 154.000000 541.000000 10.300000 1.000000
In [ ]:
# Identificar duplicados
    num_duplicates = df.duplicated().sum()
    print(f"\nNúmero de registros duplicados antes de la eliminación: {num_duplicates}")
    
    # Eliminar duplicados
    df_cleaned = df.drop_duplicates()
    
    print("\nDataFrame después de eliminar registros duplicados:")
    print(df_cleaned.head())
    
    print(f"\nNúmero de registros después de eliminar duplicados: {len(df_cleaned)}")
    df=df_cleaned
    
    Número de registros duplicados antes de la eliminación: 0
    
    DataFrame después de eliminar registros duplicados:
       Age  Gender  Heart rate  Diastolic blood pressure  Blood sugar  Troponin  \
    0   64       1          66                        83        160.0     0.012   
    1   21       1          94                        46        296.0     1.060   
    2   55       1          64                        77        270.0     0.003   
    3   64       1          70                        55        270.0     0.122   
    4   55       1          64                        65        300.0     0.003   
    
       Result  
    0       0  
    1       1  
    2       0  
    3       1  
    4       0  
    
    Número de registros después de eliminar duplicados: 1319
    

Hacemos analisis de los cuartiles con Box plots

In [ ]:
import matplotlib.pyplot as plt
    # Aplica boxplot para detectar outliers en las variables numéricas
    for col in numeric_cols:
        plt.figure(figsize=(10, 4))
        df_cleaned.boxplot(column=col)
        plt.title(f'Boxplot de {col}')
        plt.ylabel('Valor')
        plt.show()
    
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
No description has been provided for this image
In [ ]:
import matplotlib.pyplot as plt
    # Function to detect and remove outliers using IQR
    def remove_outliers_iqr(df, column):
        Q1 = df[column].quantile(0.25)
        Q3 = df[column].quantile(0.75)
        IQR = Q3 - Q1
    
        lower_bound = Q1 - 1.5 * IQR
        upper_bound = Q3 + 1.5 * IQR
    
        # Identify outliers
        outliers = df[(df[column] < lower_bound) | (df[column] > upper_bound)]
        print(f"Número de valores atípicos detectados en '{column}': {len(outliers)}")
    
        # Remove outliers
        df_cleaned = df[(df[column] >= lower_bound) & (df[column] <= upper_bound)]
        print(f"Registros después de eliminar valores atípicos en '{column}': {len(df_cleaned)}")
    
        return df_cleaned
    
    # Apply outlier removal to each numeric column
    df_no_outliers = df_cleaned.copy() # Start with the DataFrame without duplicates
    
    for col in numeric_cols:
        df_no_outliers = remove_outliers_iqr(df_no_outliers, col)
        print("-" * 30)
    
    print("\nDataFrame después de eliminar valores atípicos de todas las variables numéricas:")
    print(df_no_outliers.head())
    print(f"\nNúmero final de registros después de eliminar duplicados y valores atípicos: {len(df_no_outliers)}")
    
    # Opcionalmente, puedes visualizar los boxplots nuevamente para verificar
    for col in numeric_cols:
        plt.figure(figsize=(10, 4))
        df_no_outliers.boxplot(column=col)
        plt.title(f'Boxplot de {col} (sin atípicos)')
        plt.ylabel('Valor')
        plt.show()
    df=df_no_outliers
    
Número de valores atípicos detectados en 'Age': 7
    Registros después de eliminar valores atípicos en 'Age': 1312
    ------------------------------
    Número de valores atípicos detectados en 'Heart rate': 30
    Registros después de eliminar valores atípicos en 'Heart rate': 1282
    ------------------------------
    Número de valores atípicos detectados en 'Diastolic blood pressure': 11
    Registros después de eliminar valores atípicos en 'Diastolic blood pressure': 1271
    ------------------------------
    Número de valores atípicos detectados en 'Blood sugar': 85
    Registros después de eliminar valores atípicos en 'Blood sugar': 1186
    ------------------------------
    Número de valores atípicos detectados en 'Troponin': 231
    Registros después de eliminar valores atípicos en 'Troponin': 955
    ------------------------------
    
    DataFrame después de eliminar valores atípicos de todas las variables numéricas:
       Age  Gender  Heart rate  Diastolic blood pressure  Blood sugar  Troponin  \
    0   64       1          66                        83        160.0     0.012   
    2   55       1          64                        77        270.0     0.003   
    3   64       1          70                        55        270.0     0.122   
    5   58       0          61                        58         87.0     0.004   
    6   32       0          40                        68        102.0     0.003   
    
       Result  
    0       0  
    2       0  
    3       1  
    5       0  
    6       0  
    
    Número final de registros después de eliminar duplicados y valores atípicos: 955
    
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
No description has been provided for this image
In [ ]:
# Número de filas en el DataFrame
    print(f"\nEl DataFrame tiene {len(df)} filas.")
    
    # También puedes usar:
    # print(f"\nEl DataFrame tiene {df.shape[0]} filas.")
    
    El DataFrame tiene 955 filas.
    

Hacemos un analisis Bi variado con histogramas para estudiar la distribucion de las variables a trabajar

In [ ]:
import matplotlib.pyplot as plt
    # Histograms for numerical columns by 'Result' class
    
    # Ensure 'Result' is in the categorical columns and is encoded
    if 'Result' in numeric_cols:
        numeric_cols.remove('Result')
        if 'Result' not in categorical_cols:
            categorical_cols.append('Result') # Ensure 'Result' is treated as categorical
    
    # Apply LabelEncoder to 'Result' if it's not already encoded
    if df['Result'].dtype not in ['int64', 'float64']:
        label_encoder = LabelEncoder()
        df['Result'] = label_encoder.fit_transform(df['Result'])
        print("\n'Result' column encoded.")
        print(df[['Result']].head())
    
    
    # Get unique classes in the 'Result' column
    classes = df['Result'].unique()
    classes.sort() # Sort classes for consistent plotting order
    
    # Iterate through each numerical column
    for col in numeric_cols:
        plt.figure(figsize=(12, 6))
        plt.title(f'Histogram of {col} by Result Class')
        plt.xlabel(col)
        plt.ylabel('Frequency')
    
        # Iterate through each class in the 'Result' column
        for cls in classes:
            # Filter data for the current class
            df_class = df[df['Result'] == cls]
    
            # Plot histogram for the current class
            # Set alpha for transparency to see overlapping histograms
            plt.hist(df_class[col], bins=30, alpha=0.5, label=f'Class {cls}')
    
            # Calculate mean and median for the current class
            mean_val = df_class[col].mean()
            median_val = df_class[col].median()
    
            # Add vertical lines for mean and median
            plt.axvline(mean_val, color=plt.cm.get_cmap('viridis')(cls/len(classes)), linestyle='dashed', linewidth=1, label=f'Class {cls} Mean: {mean_val:.2f}')
            plt.axvline(median_val, color=plt.cm.get_cmap('viridis')(cls/len(classes)), linestyle='dotted', linewidth=1, label=f'Class {cls} Median: {median_val:.2f}')
    
    
        plt.legend()
        plt.grid(True, linestyle='--', alpha=0.6)
        plt.show()
    
/tmp/ipython-input-13-2526967884.py:45: MatplotlibDeprecationWarning: The get_cmap function was deprecated in Matplotlib 3.7 and will be removed in 3.11. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap()`` or ``pyplot.get_cmap()`` instead.
      plt.axvline(mean_val, color=plt.cm.get_cmap('viridis')(cls/len(classes)), linestyle='dashed', linewidth=1, label=f'Class {cls} Mean: {mean_val:.2f}')
    /tmp/ipython-input-13-2526967884.py:46: MatplotlibDeprecationWarning: The get_cmap function was deprecated in Matplotlib 3.7 and will be removed in 3.11. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap()`` or ``pyplot.get_cmap()`` instead.
      plt.axvline(median_val, color=plt.cm.get_cmap('viridis')(cls/len(classes)), linestyle='dotted', linewidth=1, label=f'Class {cls} Median: {median_val:.2f}')
    
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
No description has been provided for this image
In [ ]:
import matplotlib.pyplot as plt
    # Realizar histograma y box plot por columna numérica separada por clases ('Result')
    for col in numeric_cols:
        fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(10, 8))
    
        # Histograma en la parte superior
        axes[0].set_title(f'Histograma de {col} por clase de Resultado')
        axes[0].set_xlabel(col)
        axes[0].set_ylabel('Frecuencia')
        for cls in classes:
            axes[0].hist(df[df['Result'] == cls][col], bins=30, alpha=0.7, label=f'Clase {cls}')
        axes[0].legend(title='Clase de Resultado')
        axes[0].grid(True, linestyle='--', alpha=0.6)
    
        # Box plot horizontal en la parte inferior
        axes[1].set_title(f'Box Plot de {col} por clase de Resultado')
        axes[1].set_xlabel('Valor')
        axes[1].set_ylabel('Clase de Resultado')
        df.boxplot(column=col, by='Result', ax=axes[1], vert=False, patch_artist=True)
        plt.suptitle('') # Eliminar el título superpuesto de boxplot por defecto
        plt.tight_layout(rect=[0, 0.03, 1, 0.95]) # Ajustar el layout para evitar superposiciones
        plt.show()
    
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
No description has been provided for this image

Evaluamos la separabilidad en funcion de distintas variables

In [ ]:
import pandas as pd
    import matplotlib.pyplot as plt
    # Crear gráficos de densidad por cada variable numérica con las clases superpuestas
    
    # Asegúrate de que las variables numéricas y la columna 'Result' estén definidas correctamente
    # 'numeric_cols' debe ser una lista de nombres de columnas numéricas
    # 'Result' debe ser el nombre de la columna de clases y estar en formato numérico (codificado)
    
    # Verificar si la columna 'Result' existe y está codificada numéricamente
    if 'Result' in df.columns and pd.api.types.is_numeric_dtype(df['Result']):
        classes = df['Result'].unique()
        classes.sort()
    
        # Iterar a través de cada columna numérica
        for col in numeric_cols:
            plt.figure(figsize=(12, 6))
            plt.title(f'Gráfico de Densidad de {col} por Clase de Resultado')
            plt.xlabel(col)
            plt.ylabel('Densidad')
    
            # Iterar a través de cada clase en la columna 'Result'
            for cls in classes:
                # Filtrar datos para la clase actual
                df_class = df[df['Result'] == cls]
    
                # Trazar el gráfico de densidad (KDE plot) para la clase actual
                # Usamos .plot(kind='kde') de pandas para esto
                df_class[col].plot(kind='kde', label=f'Clase {cls}', alpha=0.7)
    
            plt.legend(title='Clase de Resultado')
            plt.grid(True, linestyle='--', alpha=0.6)
            plt.show()
    
    else:
        print("Error: La columna 'Result' no está presente o no está en un formato numérico adecuado para graficar la densidad por clases.")
        print("Asegúrate de que 'Result' se incluyó en la codificación o que es una columna numérica.")
    
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
No description has been provided for this image

Hacemos un analisis multivariado

In [ ]:
import matplotlib.pyplot as plt
    import seaborn as sns
    
    # Usa pairplot() para explorar visualmente las relaciones entre pares de variables numéricas
    # separadas por clase objetivo ('Result')
    print("\nVisualizando relaciones entre variables numéricas con pairplot:")
    sns.pairplot(df, hue='Result', diag_kind='kde')
    plt.suptitle('Pairplot de Variables Numéricas por Clase de Resultado', y=1.02)
    plt.show()
    
    Visualizando relaciones entre variables numéricas con pairplot:
    
No description has been provided for this image

Utilizamos una matriz de correlacion para evaluar la correlacion entre variables

In [ ]:
import matplotlib.pyplot as plt
    # Excluir la variable objetivo ('Result') de las variables numéricas para la matriz de correlación
    numeric_cols_for_corr = [col for col in numeric_cols if col != 'Result']
    
    # Calcular la matriz de correlación solo para las variables numéricas (sin 'Result')
    correlation_matrix = df[numeric_cols_for_corr].corr()
    
    print("\nMatriz de correlación de variables numéricas (excluyendo 'Result'):")
    print(correlation_matrix)
    
    # Visualizar la matriz de correlación usando un heatmap
    plt.figure(figsize=(12, 10))
    sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', fmt=".2f", linewidths=.5)
    plt.title('Heatmap de la Matriz de Correlación de Variables Numéricas (excluyendo "Result")')
    plt.show()
    
    Matriz de correlación de variables numéricas (excluyendo 'Result'):
                                   Age  Heart rate  Diastolic blood pressure  \
    Age                       1.000000   -0.013521                 -0.028200   
    Heart rate               -0.013521    1.000000                  0.136120   
    Diastolic blood pressure -0.028200    0.136120                  1.000000   
    Blood sugar              -0.013610    0.011173                  0.017895   
    Troponin                  0.223293    0.000487                  0.000586   
    
                              Blood sugar  Troponin  
    Age                         -0.013610  0.223293  
    Heart rate                   0.011173  0.000487  
    Diastolic blood pressure     0.017895  0.000586  
    Blood sugar                  1.000000 -0.009831  
    Troponin                    -0.009831  1.000000  
    
No description has been provided for this image

Generamos un reporte de significancia entre variables

In [ ]:
import pandas as pd
    from scipy.stats import chi2_contingency
    
    # Asegúrate de que 'Result' está en las columnas categóricas o la trataremos como tal
    # Si 'Result' fue movida a numéricas anteriormente, la volvemos a considerar categórica
    # basándonos en la tarea (análisis con Chi-cuadrado sobre variables Categóricas vs. Result)
    if 'Result' not in categorical_cols and 'Result' in df.columns:
         # Si 'Result' está en el DataFrame pero no en categorical_cols, la añadimos
         # Esto puede pasar si 'Result' fue tratada como numérica en alguna parte del código anterior
         categorical_cols.append('Result')
         if 'Result' in numeric_cols:
              numeric_cols.remove('Result') # Remover de numéricas si estaba ahí por error para este análisis
    
    
    # Lista para almacenar los resultados del test de Chi-cuadrado
    chi2_results = {}
    
    # Nivel de significancia (alpha)
    alpha = 0.05
    
    print("\nRealizando Test de Chi-cuadrado para Variables Categóricas vs. Result:")
    print("-" * 60)
    
    # Iterar sobre cada variable categórica (excluyendo 'Result')
    for col in categorical_cols:
        if col != 'Result':
            print(f"Analizando la relación entre '{col}' y 'Result'...")
    
            # Crear la tabla de contingencia
            contingency_table = pd.crosstab(df[col], df['Result'])
    
            # Asegurarse de que la tabla no esté vacía
            if contingency_table.shape[0] > 1 and contingency_table.shape[1] > 1:
                # Realizar el test de Chi-cuadrado
                chi2, p, dof, ex = chi2_contingency(contingency_table)
    
                # Almacenar los resultados
                chi2_results[col] = {'chi2': chi2, 'p_value': p, 'dof': dof}
    
                # Imprimir el resultado y determinar la significancia
                print(f"  Estadístico Chi-cuadrado: {chi2:.4f}")
                print(f"  Valor p: {p:.4f}")
                print(f"  Grados de libertad: {dof}")
    
                if p < alpha:
                    print(f"  Conclusión: '{col}' es SIGNIFICATIVA (p < {alpha}) - Hay una asociación estadísticamente significativa con 'Result'.")
                else:
                    print(f"  Conclusión: '{col}' NO es SIGNIFICATIVA (p >= {alpha}) - No hay evidencia suficiente de asociación con 'Result'.")
            else:
                print(f"  No se puede realizar el test de Chi-cuadrado para '{col}': La tabla de contingencia es demasiado pequeña ({contingency_table.shape}).")
    
            print("-" * 60)
    
    # Reporte final de variables significativas y no significativas
    print("\nReporte de Significancia (Nivel alpha = 0.05):")
    print("-" * 40)
    
    significant_vars = [var for var, res in chi2_results.items() if res['p_value'] < alpha]
    non_significant_vars = [var for var, res in chi2_results.items() if res['p_value'] >= alpha]
    
    print("Variables Categóricas Significativas (asociación con 'Result'):")
    if significant_vars:
        for var in significant_vars:
            print(f"- {var} (Valor p: {chi2_results[var]['p_value']:.4f})")
    else:
        print("Ninguna variable categórica fue estadísticamente significativa.")
    
    print("\nVariables Categóricas NO Significativas (sin asociación con 'Result'):")
    if non_significant_vars:
         # También incluimos variables que no pudieron ser testeadas
        non_significant_vars.extend([col for col in categorical_cols if col != 'Result' and col not in chi2_results])
        for var in set(non_significant_vars): # Usamos set para evitar duplicados si una variable no pudo ser testeada
             if var in chi2_results:
                 print(f"- {var} (Valor p: {chi2_results[var]['p_value']:.4f})")
             else:
                  print(f"- {var} (No se pudo testear, tabla de contingencia insuficiente)")
    else:
        print("Todas las variables categóricas testeadas fueron estadísticamente significativas.")
    
    print("-" * 40)
    
    Realizando Test de Chi-cuadrado para Variables Categóricas vs. Result:
    ------------------------------------------------------------
    Analizando la relación entre 'Gender' y 'Result'...
      Estadístico Chi-cuadrado: 5.1954
      Valor p: 0.0226
      Grados de libertad: 1
      Conclusión: 'Gender' es SIGNIFICATIVA (p < 0.05) - Hay una asociación estadísticamente significativa con 'Result'.
    ------------------------------------------------------------
    
    Reporte de Significancia (Nivel alpha = 0.05):
    ----------------------------------------
    Variables Categóricas Significativas (asociación con 'Result'):
    - Gender (Valor p: 0.0226)
    
    Variables Categóricas NO Significativas (sin asociación con 'Result'):
    Todas las variables categóricas testeadas fueron estadísticamente significativas.
    ----------------------------------------
    

Aplicamos las pruebas t stutent y el ANOVA para evaluar la significancia entre variables numericas

In [ ]:
import pandas as pd
    from scipy import stats
    
    print("\nRealizando pruebas estadísticas (t-student o ANOVA) para Variables Numéricas vs. Result:")
    print("-" * 80)
    
    # Nivel de significancia (alpha)
    alpha = 0.05
    
    # Asegurarse de que 'Result' está presente y es numérica para este análisis
    if 'Result' in df.columns and pd.api.types.is_numeric_dtype(df['Result']):
        # Obtener las clases únicas de 'Result'
        result_classes = df['Result'].unique()
        num_classes = len(result_classes)
    
        # Iterar sobre cada variable numérica
        for col in numeric_cols:
            print(f"Analizando la relación entre '{col}' y 'Result' ({num_classes} clases)...")
    
            # Crear una lista de series, una por cada grupo de 'Result'
            groups = [df[col][df['Result'] == cls].dropna() for cls in result_classes]
    
            # Verificar si los grupos tienen suficientes datos
            valid_groups = [group for group in groups if len(group) > 1]
    
            if len(valid_groups) == num_classes: # Solo procedemos si todos los grupos tienen datos > 1
                if num_classes == 2:
                    # Aplicar T-student si hay exactamente 2 clases en 'Result'
                    print(f"  Aplicando prueba t-student (2 clases en 'Result')...")
                    try:
                        # Realizar el test t-student independiente
                        # asume varianzas iguales; para asumir desiguales use equal_var=False
                        t_statistic, p_value = stats.ttest_ind(valid_groups[0], valid_groups[1], nan_policy='omit')
    
                        print(f"  Estadístico T: {t_statistic:.4f}")
                        print(f"  Valor p: {p_value:.4f}")
    
                        # Determinar significancia
                        if p_value < alpha:
                            print(f"  Conclusión: '{col}' es SIGNIFICATIVA (p < {alpha}) - Hay una diferencia promedio estadísticamente significativa entre los grupos de 'Result'.")
                        else:
                            print(f"  Conclusión: '{col}' NO es SIGNIFICATIVA (p >= {alpha}) - No hay evidencia suficiente de diferencia promedio entre los grupos de 'Result'.")
    
                    except Exception as e:
                        print(f"  Error al realizar la prueba t-student para '{col}': {e}")
    
                elif num_classes > 2:
                    # Aplicar ANOVA si hay más de 2 clases en 'Result'
                    print(f"  Aplicando prueba ANOVA ({num_classes} clases en 'Result')...")
                    try:
                        # Realizar el test ANOVA
                        f_statistic, p_value = stats.f_oneway(*valid_groups)
    
                        print(f"  Estadístico F: {f_statistic:.4f}")
                        print(f"  Valor p: {p_value:.4f}")
    
                        # Determinar significancia
                        if p_value < alpha:
                            print(f"  Conclusión: '{col}' es SIGNIFICATIVA (p < {alpha}) - Hay al menos un grupo de 'Result' cuya media difiere significativamente de las otras.")
                        else:
                            print(f"  Conclusión: '{col}' NO es SIGNIFICATIVA (p >= {alpha}) - No hay evidencia suficiente de que las medias de los grupos de 'Result' difieran.")
    
                    except Exception as e:
                         print(f"  Error al realizar la prueba ANOVA para '{col}': {e}")
    
                else:
                    print(f"  No se puede realizar la prueba estadística para '{col}': El número de clases de 'Result' ({num_classes}) no es 2 o más de 2.")
            else:
                 print(f"  No se puede realizar la prueba estadística para '{col}': No hay suficientes datos en algunos grupos de 'Result'.")
    
    
            print("-" * 80)
    
    else:
        print("Error: La columna 'Result' no está presente o no está en un formato numérico adecuado para realizar pruebas t-student o ANOVA.")
        print("Asegúrate de que 'Result' fue codificada numéricamente.")
    
    # Reporte final de variables numéricas significativas y no significativas (basado en las pruebas realizadas)
    print("\nReporte de Significancia para Variables Numéricas (Nivel alpha = 0.05):")
    print("-" * 60)
    
    significant_numeric_vars = []
    non_significant_numeric_vars = []
    untested_numeric_vars = []
    
    # Re-iterar o almacenar los resultados para el reporte final si se desea
    # Este snippet solo imprime durante la ejecución. Para un reporte consolidado,
    # se deberían almacenar los resultados de p_value en un diccionario o lista.
    
    # Ejemplo de cómo podrías estructurarlo (requiere modificar el bucle anterior para almacenar):
    # numeric_test_results = {} # Diccionario para almacenar p-values de tests numéricos
    
    # Después del bucle de t-student/ANOVA:
    # print("Variables Numéricas Significativas (asociación con 'Result'):")
    # sig_num = [var for var, p in numeric_test_results.items() if p < alpha]
    # if sig_num:
    #     for var in sig_num:
    #         print(f"- {var} (Valor p: {numeric_test_results[var]:.4f})")
    # else:
    #     print("Ninguna variable numérica fue estadísticamente significativa.")
    
    # print("\nVariables Numéricas NO Significativas (sin asociación con 'Result'):")
    # non_sig_num = [var for var, p in numeric_test_results.items() if p >= alpha]
    # if non_sig_num:
    #      print("Variables testeadas como no significativas:")
    #      for var in non_sig_num:
    #         print(f"- {var} (Valor p: {numeric_test_results[var]:.4f})")
    # else:
    #     print("Todas las variables numéricas testeadas fueron estadísticamente significativas.")
    
    # print("\nVariables Numéricas NO testeadas (por falta de datos en grupos, etc.):")
    # # Aquí necesitarías una lista de variables que no pudieron ser testeadas
    # # untested_num = ...
    # if untested_numeric_vars:
    #      for var in untested_numeric_vars:
    #           print(f"- {var}")
    # else:
    #      print("Todas las variables numéricas fueron testeadas.")
    
    
    # Como el código anterior no almacena los resultados centralmente,
    # simplemente resumimos lo que se imprimió:
    print("Consulta los resultados detallados de cada variable numérica y su valor p en la salida anterior.")
    print("Las variables con un 'Valor p' menor a 0.05 se consideran significativas.")
    
    print("-" * 60)
    
    Realizando pruebas estadísticas (t-student o ANOVA) para Variables Numéricas vs. Result:
    --------------------------------------------------------------------------------
    Analizando la relación entre 'Age' y 'Result' (2 clases)...
      Aplicando prueba t-student (2 clases en 'Result')...
      Estadístico T: -7.7594
      Valor p: 0.0000
      Conclusión: 'Age' es SIGNIFICATIVA (p < 0.05) - Hay una diferencia promedio estadísticamente significativa entre los grupos de 'Result'.
    --------------------------------------------------------------------------------
    Analizando la relación entre 'Heart rate' y 'Result' (2 clases)...
      Aplicando prueba t-student (2 clases en 'Result')...
      Estadístico T: 0.8164
      Valor p: 0.4145
      Conclusión: 'Heart rate' NO es SIGNIFICATIVA (p >= 0.05) - No hay evidencia suficiente de diferencia promedio entre los grupos de 'Result'.
    --------------------------------------------------------------------------------
    Analizando la relación entre 'Diastolic blood pressure' y 'Result' (2 clases)...
      Aplicando prueba t-student (2 clases en 'Result')...
      Estadístico T: 1.5280
      Valor p: 0.1269
      Conclusión: 'Diastolic blood pressure' NO es SIGNIFICATIVA (p >= 0.05) - No hay evidencia suficiente de diferencia promedio entre los grupos de 'Result'.
    --------------------------------------------------------------------------------
    Analizando la relación entre 'Blood sugar' y 'Result' (2 clases)...
      Aplicando prueba t-student (2 clases en 'Result')...
      Estadístico T: 0.3414
      Valor p: 0.7329
      Conclusión: 'Blood sugar' NO es SIGNIFICATIVA (p >= 0.05) - No hay evidencia suficiente de diferencia promedio entre los grupos de 'Result'.
    --------------------------------------------------------------------------------
    Analizando la relación entre 'Troponin' y 'Result' (2 clases)...
      Aplicando prueba t-student (2 clases en 'Result')...
      Estadístico T: -15.7832
      Valor p: 0.0000
      Conclusión: 'Troponin' es SIGNIFICATIVA (p < 0.05) - Hay una diferencia promedio estadísticamente significativa entre los grupos de 'Result'.
    --------------------------------------------------------------------------------
    
    Reporte de Significancia para Variables Numéricas (Nivel alpha = 0.05):
    ------------------------------------------------------------
    Consulta los resultados detallados de cada variable numérica y su valor p en la salida anterior.
    Las variables con un 'Valor p' menor a 0.05 se consideran significativas.
    ------------------------------------------------------------
    
In [ ]:
# Guardar el DataFrame final en un archivo CSV
    df.to_csv('dataframe_final.csv', index=False,sep=";")
    
    # Guardar las listas de variables numéricas y categóricas
    import json
    
    variables_info = {
        'numeric_variables': numeric_cols,
        'categorical_variables': categorical_cols
    }
    
    with open('variables_info.json', 'w') as f:
        json.dump(variables_info, f, indent=4)
    
    print("\nDataFrame final guardado como 'dataframe_final.csv'")
    print("Listas de variables numéricas y categóricas guardadas como 'variables_info.json'")
    
    DataFrame final guardado como 'dataframe_final.csv'
    Listas de variables numéricas y categóricas guardadas como 'variables_info.json'