Estadistica Basica Aplicada con Python¶
Script de Analisis Estadistico — Semana 6¶
| Titulo | Analisis Estadistico del Dataset de Diabetes |
| Estudiante | Alexander Oviedo Fadul |
| Curso | Fundamentos para Inteligencia Artificial (NRC-197) |
| Semana | 6 |
| Docente | Breyner Alexander Parra Rojas |
| Fecha de entrega | 23 de febrero de 2026 |
| Institucion | UNIMINUTO |
| URL Google Colab | https://colab.research.google.com/drive/1t0cVBHLYSnnHGhOO_wBuX_TQNI3mkDA9 |
1. Introduccion y Contexto¶
Esta semana el profesor Breyner abrio el tema de la estadistica inferencial: esa diferencia entre describir lo que ya paso y atreverse a predecir lo que podria pasar. El ejemplo del futbol me quedo dando vueltas: sacar a un jugador porque el modelo detecta riesgo de desgarro no es certeza, es probabilidad. Eso mismo ocurre con mi trabajo en la Rama Judicial.
En el proyecto MARDUK usamos estadistica descriptiva a diario para reportar tiempos de resolucion de tutelas y cargas laborales. Pero la pregunta de los directivos es siempre otra: cuando se va a resolver este represamiento. Ahi entra la estadistica inferencial.
Para esta actividad seleccione el Dataset de Diabetes (NCSU) disponible en scikit-learn, con 442 pacientes y 10 variables. Me parecio adecuado porque, como en el sistema judicial, aqui tambien tenemos datos humanos complejos con ruido, variabilidad y sesgos posibles, exactamente los retos que el docente senalo en clase (Cady, 2020, pp. 58-60).
El objetivo es aplicar un analisis estadistico completo: medidas de posicion central, relacion entre medias, posicion no central, dispersion, asimetria, curtosis, frecuencias y visualizaciones, tal como lo indica la actividad.
Referencias de esta seccion: Cady (2020, pp. 55-56) argumenta que los resúmenes simples de datos, bien ejecutados, producen mas valor practico que tecnicas matematicas complejas mal aplicadas.
2. Importacion de Librerias y Configuracion¶
# ============================================================
# IMPORTACION DE LIBRERIAS DEL ECOSISTEMA CIENTIFICO PYTHON
#
# Boschetti y Massaron (2018, pp. 282-284) describen este
# conjunto de librerias como el nucleo indispensable para
# cualquier analisis de datos en Python.
#
# - numpy : operaciones numericas vectorizadas y eficientes
# - pandas : estructuras de datos tipo DataFrame para EDA
# - matplotlib: visualizacion base (graficos de bajo nivel)
# - seaborn : visualizacion estadistica de alto nivel sobre matplotlib
# - scipy.stats: funciones estadisticas (skewness, kurtosis, medias)
# - sklearn.datasets: acceso al dataset de diabetes
# ============================================================
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
from sklearn.datasets import load_diabetes
# Configuracion visual global
# Boschetti y Massaron (2018, pp. 304-310) recomiendan definir
# el estilo y la paleta una sola vez para coherencia visual.
plt.style.use('seaborn-v0_8-whitegrid')
sns.set_palette('muted')
plt.rcParams['figure.figsize'] = (10, 5)
plt.rcParams['font.size'] = 11
print('Librerias importadas correctamente.')
print(f'NumPy: {np.__version__} | Pandas: {pd.__version__}')
Librerias importadas correctamente. NumPy: 2.0.2 | Pandas: 2.2.2
3. Carga y Descripcion del Dataset¶
# ============================================================
# CARGA DEL DATASET DE DIABETES (NCSU / SKLEARN)
#
# Fuente original: Efron, B., Hastie, T., Johnstone, I., y
# Tibshirani, R. (2004). Least angle regression.
# Annals of Statistics, 32(2), 407-499.
# URL: https://www4.stat.ncsu.edu/~boos/var.select/diabetes.html
#
# El dataset contiene 442 observaciones y 10 variables predictoras
# (todas estandarizadas: media=0, std=1), mas una variable objetivo
# numerica que mide la progresion de la diabetes al anyo siguiente.
#
# Fuentes (2018, pp. 122-124) senala que la inspeccion inicial
# del dataset es el primer paso critico antes de cualquier calculo.
# ============================================================
diabetes_raw = load_diabetes()
# Construir DataFrame con nombres de columnas descriptivos
df = pd.DataFrame(data=diabetes_raw.data, columns=diabetes_raw.feature_names)
df['target'] = diabetes_raw.target # variable objetivo: progresion de la enfermedad
# Descripcion de variables
variables_desc = {
'age': 'Edad del paciente (estandarizada)',
'sex': 'Sexo del paciente (estandarizado)',
'bmi': 'Indice de Masa Corporal (estandarizado)',
'bp': 'Presion arterial media (estandarizada)',
's1': 'Colesterol total en suero (estandarizado)',
's2': 'Colesterol LDL (estandarizado)',
's3': 'Colesterol HDL (estandarizado)',
's4': 'Coeficiente colesterol total / HDL (estandarizado)',
's5': 'Logaritmo de trigliceridos sericos (estandarizado)',
's6': 'Glucosa en sangre (estandarizada)',
'target': 'Progresion de la diabetes al siguiente anyo (25-346)'
}
print('Primeras filas del dataset:')
print(df.head())
print(f'\nDimensiones: {df.shape[0]} filas x {df.shape[1]} columnas')
print(f'\nVerificacion de valores faltantes (gestion de datos incompletos, clase 21/02/2026):')
print(df.isnull().sum())
print('\nNo hay valores faltantes. En datasets reales se aplicarian estrategias de imputacion')
print('(media, mediana, cuartiles) segun lo discutido en clase.')
Primeras filas del dataset:
age sex bmi bp s1 s2 s3 \
0 0.038076 0.050680 0.061696 0.021872 -0.044223 -0.034821 -0.043401
1 -0.001882 -0.044642 -0.051474 -0.026328 -0.008449 -0.019163 0.074412
2 0.085299 0.050680 0.044451 -0.005670 -0.045599 -0.034194 -0.032356
3 -0.089063 -0.044642 -0.011595 -0.036656 0.012191 0.024991 -0.036038
4 0.005383 -0.044642 -0.036385 0.021872 0.003935 0.015596 0.008142
s4 s5 s6 target
0 -0.002592 0.019907 -0.017646 151.0
1 -0.039493 -0.068332 -0.092204 75.0
2 -0.002592 0.002861 -0.025930 141.0
3 0.034309 0.022688 -0.009362 206.0
4 -0.002592 -0.031988 -0.046641 135.0
Dimensiones: 442 filas x 11 columnas
Verificacion de valores faltantes (gestion de datos incompletos, clase 21/02/2026):
age 0
sex 0
bmi 0
bp 0
s1 0
s2 0
s3 0
s4 0
s5 0
s6 0
target 0
dtype: int64
No hay valores faltantes. En datasets reales se aplicarian estrategias de imputacion
(media, mediana, cuartiles) segun lo discutido en clase.
4. Medidas de Posicion Central¶
Las medidas de posicion central resumen el punto de concentracion de los datos. Cady (2020, pp. 63-65) distingue sus usos: la media asume distribucion simetrica; la mediana es robusta ante valores atipicos; la moda identifica el valor mas frecuente.
# ============================================================
# MEDIDAS DE POSICION CENTRAL — Variable: target
#
# Media aritmetica: suma de todos los valores / n observaciones.
# Representa el 'centro de gravedad' de los datos.
# Sensible a valores atipicos extremos (Cady, 2020, p. 63).
#
# Mediana: valor que divide el conjunto ordenado en dos mitades iguales.
# Estadistico robusto; insensible a outliers (Cady, 2020, p. 65).
#
# Moda: valor que aparece con mayor frecuencia.
# Fuentes (2018, p. 123) la calcula con scipy.stats.mode.
# ============================================================
target = df['target']
media = np.mean(target)
mediana = np.median(target)
moda = stats.mode(target, keepdims=True).mode[0]
print('MEDIDAS DE POSICION CENTRAL — Variable: progresion de diabetes (target)')
print('-' * 55)
print(f'Media aritmetica : {media:.4f}')
print(f'Mediana : {mediana:.4f}')
print(f'Moda : {moda:.4f}')
print('-' * 55)
# Interpretacion de la relacion media-mediana
# Una diferencia significativa indica asimetria en la distribucion
if abs(media - mediana) < 5:
print('Interpretacion: distribucion aproximadamente simetrica (media ~ mediana).')
elif media > mediana:
print('Interpretacion: media > mediana. Distribucion con sesgo positivo (cola derecha).')
else:
print('Interpretacion: media < mediana. Distribucion con sesgo negativo (cola izquierda).')
MEDIDAS DE POSICION CENTRAL — Variable: progresion de diabetes (target) ------------------------------------------------------- Media aritmetica : 152.1335 Mediana : 140.5000 Moda : 72.0000 ------------------------------------------------------- Interpretacion: media > mediana. Distribucion con sesgo positivo (cola derecha).
5. Relacion entre Medias¶
Cady (2020, pp. 63-65) senala que elegir el tipo de media correcto depende del tipo de datos. La media geometrica es adecuada para tasas de crecimiento; la armonica para promedios de tasas inversas.
# ============================================================
# RELACION ENTRE MEDIAS
#
# Media aritmetica: promedio clasico. Se ve afectada por outliers.
#
# Media geometrica: raiz n-esima del producto de los n valores.
# Util para datos con crecimiento exponencial o proporcional.
# Se calcula con scipy.stats.gmean (Fuentes, 2018, p. 124).
#
# Media armonica: n / suma(1/xi). Adecuada para promediar tasas
# y velocidades. Se calcula con scipy.stats.hmean.
#
# Propiedad matematica fundamental:
# Media armonica <= Media geometrica <= Media aritmetica
# Esta desigualdad se verifica empiricamente a continuacion.
# ============================================================
target_pos = target[target > 0] # medias geometrica y armonica requieren valores positivos
media_arit = np.mean(target_pos)
media_geom = stats.gmean(target_pos)
media_arm = stats.hmean(target_pos)
print('RELACION ENTRE MEDIAS — Variable: target (valores positivos)')
print('-' * 55)
print(f'Media aritmetica : {media_arit:.4f}')
print(f'Media geometrica : {media_geom:.4f}')
print(f'Media armonica : {media_arm:.4f}')
print('-' * 55)
cumple = media_arm <= media_geom <= media_arit
print(f'Propiedad MA <= MG <= MArit verificada: {cumple}')
print('Nota: la diferencia entre medias indica variabilidad no linealmente distribuida.')
RELACION ENTRE MEDIAS — Variable: target (valores positivos) ------------------------------------------------------- Media aritmetica : 152.1335 Media geometrica : 131.8049 Media armonica : 112.1427 ------------------------------------------------------- Propiedad MA <= MG <= MArit verificada: True Nota: la diferencia entre medias indica variabilidad no linealmente distribuida.
6. Medidas de Posicion No Central (Cuantiles)¶
Los cuantiles dividen el conjunto de datos en fracciones iguales. Los cuartiles, en particular, son la base del diagrama de caja y de la deteccion de valores atipicos mediante el metodo de Tukey (Cady, 2020, pp. 65-68).
# ============================================================
# MEDIDAS DE POSICION NO CENTRAL
#
# Cuartil 1 (Q1 = P25): el 25% de los datos esta por debajo.
# Cuartil 2 (Q2 = P50): coincide con la mediana.
# Cuartil 3 (Q3 = P75): el 75% de los datos esta por debajo.
# IQR (rango intercuartilico): Q3 - Q1. Mide la dispersion
# del 50% central de los datos. Resistente a outliers.
#
# Metodo Tukey para identificar valores atipicos:
# Limite inferior = Q1 - 1.5 * IQR
# Limite superior = Q3 + 1.5 * IQR
# Valores fuera de estos limites se consideran outliers.
# (Cady, 2020, pp. 58-60; Boschetti y Massaron, 2018, p. 297)
# ============================================================
Q1 = np.percentile(target, 25)
Q2 = np.percentile(target, 50)
Q3 = np.percentile(target, 75)
IQR = Q3 - Q1
P10 = np.percentile(target, 10)
P90 = np.percentile(target, 90)
lim_inf = Q1 - 1.5 * IQR
lim_sup = Q3 + 1.5 * IQR
outliers = target[(target < lim_inf) | (target > lim_sup)]
print('MEDIDAS DE POSICION NO CENTRAL — Variable: target')
print('-' * 55)
print(f'Q1 (Cuartil 1 — P25) : {Q1:.2f}')
print(f'Q2 (Mediana — P50) : {Q2:.2f}')
print(f'Q3 (Cuartil 3 — P75) : {Q3:.2f}')
print(f'IQR (Q3 - Q1) : {IQR:.2f}')
print(f'Percentil 10 : {P10:.2f}')
print(f'Percentil 90 : {P90:.2f}')
print(f'Limite inferior (Tukey) : {lim_inf:.2f}')
print(f'Limite superior (Tukey) : {lim_sup:.2f}')
print(f'Valores atipicos (outliers): {len(outliers)}')
print('-' * 55)
print(f'El 50% central de los pacientes tiene una progresion entre {Q1:.0f} y {Q3:.0f}.')
print(f'Los {len(outliers)} outliers merecen analisis individual (posibles comorbilidades).')
MEDIDAS DE POSICION NO CENTRAL — Variable: target ------------------------------------------------------- Q1 (Cuartil 1 — P25) : 87.00 Q2 (Mediana — P50) : 140.50 Q3 (Cuartil 3 — P75) : 211.50 IQR (Q3 - Q1) : 124.50 Percentil 10 : 60.00 Percentil 90 : 265.00 Limite inferior (Tukey) : -99.75 Limite superior (Tukey) : 398.25 Valores atipicos (outliers): 0 ------------------------------------------------------- El 50% central de los pacientes tiene una progresion entre 87 y 212. Los 0 outliers merecen analisis individual (posibles comorbilidades).
7. Medidas de Dispersion¶
La dispersion indica que tan esparcidos estan los datos alrededor de la media. Cady (2020, pp. 65-68) explica que el coeficiente de variacion (CV) es el estadistico mas util para comparar dispersiones entre variables de distintas escalas.
# ============================================================
# MEDIDAS DE DISPERSION
#
# Rango: diferencia entre valor maximo y minimo.
# Es la medida mas sencilla de dispersion, pero muy sensible
# a valores extremos y poco informativa en solitario.
#
# Varianza muestral (ddof=1): promedio de cuadrados de las
# desviaciones respecto a la media. Se usa ddof=1 (correccion
# de Bessel) para obtener un estimador insesgado de la varianza
# poblacional cuando se trabaja con una muestra.
#
# Desviacion estandar: raiz cuadrada de la varianza.
# Tiene las mismas unidades que los datos originales, lo que
# facilita su interpretacion practica.
#
# Coeficiente de variacion (CV = desv/media * 100):
# Mide la variabilidad relativa, independiente de la escala.
# Fuentes (2018, p. 123) lo usa para comparar variables.
# CV < 15%: baja dispersion (datos homogeneos)
# 15% <= CV < 30%: dispersion media
# CV >= 30%: alta dispersion (datos heterogeneos)
#
# Error estandar (SE = desv/sqrt(n)):
# Mide la precision de la media muestral como estimador de
# la media poblacional. Relacionado con los intervalos de
# confianza discutidos en clase (Cady, 2020, p. 82).
# ============================================================
rango = target.max() - target.min()
varianza = np.var(target, ddof=1)
desv_std = np.std(target, ddof=1)
cv = (desv_std / media) * 100
error_std = desv_std / np.sqrt(len(target))
print('MEDIDAS DE DISPERSION — Variable: target')
print('-' * 55)
print(f'Valor minimo : {target.min():.2f}')
print(f'Valor maximo : {target.max():.2f}')
print(f'Rango : {rango:.2f}')
print(f'Varianza (muestral) : {varianza:.4f}')
print(f'Desviacion estandar : {desv_std:.4f}')
print(f'Coeficiente de variacion: {cv:.2f}%')
print(f'Error estandar (SE) : {error_std:.4f}')
print('-' * 55)
if cv < 15:
cv_interp = 'baja (datos homogeneos)'
elif cv < 30:
cv_interp = 'media (heterogeneidad moderada)'
else:
cv_interp = 'alta (datos muy heterogeneos)'
print(f'El CV del {cv:.1f}% indica dispersion {cv_interp}.')
print('En datos clinicos esta variabilidad es esperable dado el perfil diverso de los pacientes.')
MEDIDAS DE DISPERSION — Variable: target ------------------------------------------------------- Valor minimo : 25.00 Valor maximo : 346.00 Rango : 321.00 Varianza (muestral) : 5943.3313 Desviacion estandar : 77.0930 Coeficiente de variacion: 50.67% Error estandar (SE) : 3.6669 ------------------------------------------------------- El CV del 50.7% indica dispersion alta (datos muy heterogeneos). En datos clinicos esta variabilidad es esperable dado el perfil diverso de los pacientes.
8. Asimetria y Curtosis¶
La asimetria y la curtosis caracterizan la forma de la distribucion.
Fuentes (2018, pp. 127-130) explica estos estadisticos usando scipy.stats
y senala su importancia para decidir que pruebas estadisticas aplicar.
# ============================================================
# ASIMETRIA Y CURTOSIS
#
# Asimetria (Skewness):
# Mide la falta de simetria de la distribucion.
# = 0 : distribucion simetrica
# > 0 : asimetria positiva (cola hacia la derecha)
# < 0 : asimetria negativa (cola hacia la izquierda)
# |asimetria| < 0.5 : aproximadamente simetrica
# (Fuentes, 2018, p. 127)
#
# Curtosis (Kurtosis) — exceso de Fisher:
# Mide el peso de las colas comparado con la normal.
# = 0 : mesocurtica (igual que la normal)
# > 0 : leptocurtica (colas mas pesadas, picos mas altos)
# < 0 : platicurtica (colas mas ligeras, distribucion mas plana)
# Se usa fisher=True para obtener el exceso de curtosis.
# (Fuentes, 2018, pp. 127-130)
#
# Relevancia para IA: si la distribucion no es normal, algoritmos
# basados en ese supuesto (regresion lineal OLS) requieren
# transformaciones previas de los datos.
# ============================================================
asimetria = stats.skew(target)
curtosis = stats.kurtosis(target, fisher=True)
print('ASIMETRIA Y CURTOSIS — Variable: target')
print('-' * 55)
print(f'Asimetria (Skewness) : {asimetria:.4f}')
print(f'Curtosis (Fisher) : {curtosis:.4f}')
print('-' * 55)
if abs(asimetria) < 0.5:
asim_desc = 'aproximadamente simetrica'
elif asimetria > 0:
asim_desc = 'asimetria positiva (sesgo a la derecha)'
else:
asim_desc = 'asimetria negativa (sesgo a la izquierda)'
if abs(curtosis) < 0.5:
kurt_desc = 'mesocurtica (normal)'
elif curtosis > 0:
kurt_desc = 'leptocurtica (colas pesadas)'
else:
kurt_desc = 'platicurtica (colas ligeras)'
print(f'Distribucion: {asim_desc}.')
print(f'Tipo de curtosis: {kurt_desc}.')
ASIMETRIA Y CURTOSIS — Variable: target ------------------------------------------------------- Asimetria (Skewness) : 0.4391 Curtosis (Fisher) : -0.8866 ------------------------------------------------------- Distribucion: aproximadamente simetrica. Tipo de curtosis: platicurtica (colas ligeras).
9. Distribucion de Frecuencias¶
Boschetti y Massaron (2018, pp. 291-292) presentan los histogramas y tablas de frecuencias como el primer paso del EDA para entender la distribucion de una variable.
# ============================================================
# TABLA DE DISTRIBUCION DE FRECUENCIAS
#
# Se agrupan los valores continuos de target en 8 intervalos
# de igual amplitud usando numpy.histogram.
#
# Frecuencia absoluta : numero de observaciones en cada intervalo
# Frecuencia relativa : proporcion del total (en porcentaje)
# Frecuencia acumulada : suma progresiva de frecuencias absolutas
# Frec. relativa acum. : suma progresiva de frecuencias relativas
# ============================================================
num_bins = 8
frec_abs, bordes = np.histogram(target, bins=num_bins)
frec_rel = frec_abs / len(target) * 100
frec_acum = np.cumsum(frec_abs)
frec_racum = np.cumsum(frec_rel)
tabla_freq = pd.DataFrame({
'Intervalo': [f'[{bordes[i]:.0f} - {bordes[i+1]:.0f})' for i in range(num_bins)],
'Punto Medio': [(bordes[i] + bordes[i+1]) / 2 for i in range(num_bins)],
'Frec. Absoluta': frec_abs,
'Frec. Relativa (%)': frec_rel.round(2),
'Frec. Acumulada': frec_acum,
'Frec. Rel. Acum. (%)': frec_racum.round(2)
})
print('TABLA DE FRECUENCIAS — Variable: target (Progresion de Diabetes)')
print('=' * 78)
print(tabla_freq.to_string(index=False))
print('=' * 78)
print(f'Total de observaciones: {len(target)}')
TABLA DE FRECUENCIAS — Variable: target (Progresion de Diabetes) ============================================================================== Intervalo Punto Medio Frec. Absoluta Frec. Relativa (%) Frec. Acumulada Frec. Rel. Acum. (%) [25 - 65) 45.0625 59 13.35 59 13.35 [65 - 105) 85.1875 101 22.85 160 36.20 [105 - 145) 125.3125 75 16.97 235 53.17 [145 - 186) 165.4375 63 14.25 298 67.42 [186 - 226) 205.5625 51 11.54 349 78.96 [226 - 266) 245.6875 49 11.09 398 90.05 [266 - 306) 285.8125 32 7.24 430 97.29 [306 - 346) 325.9375 12 2.71 442 100.00 ============================================================================== Total de observaciones: 442
10. Resumen Estadistico Completo¶
# ============================================================
# RESUMEN ESTADISTICO CON PANDAS
#
# El metodo describe() de Pandas genera automaticamente
# conteo, media, desviacion estandar, minimo, cuartiles
# y maximo para cada variable numerica del DataFrame.
# Es el punto de partida recomendado por Fuentes (2018, p. 122)
# y Boschetti y Massaron (2018, p. 296) para cualquier EDA.
# ============================================================
print('Resumen estadistico de todas las variables:')
print(df.describe().round(4).T.to_string())
# Tabla resumen integrada con todas las metricas calculadas
resumen = pd.DataFrame({
'Metrica': [
'Media aritmetica', 'Mediana', 'Moda',
'Media geometrica', 'Media armonica',
'Q1 (P25)', 'Q2 (P50)', 'Q3 (P75)', 'IQR',
'Percentil 10', 'Percentil 90',
'Minimo', 'Maximo', 'Rango',
'Varianza (muestral)', 'Desviacion estandar',
'Coef. de variacion (%)', 'Error estandar',
'Asimetria (Skewness)', 'Curtosis (Fisher)',
'N observaciones', 'Outliers (Tukey)'
],
'Valor': [
f'{media:.4f}', f'{mediana:.4f}', f'{moda:.4f}',
f'{media_geom:.4f}', f'{media_arm:.4f}',
f'{Q1:.4f}', f'{Q2:.4f}', f'{Q3:.4f}', f'{IQR:.4f}',
f'{P10:.4f}', f'{P90:.4f}',
f'{target.min():.4f}', f'{target.max():.4f}', f'{rango:.4f}',
f'{varianza:.4f}', f'{desv_std:.4f}',
f'{cv:.2f}%', f'{error_std:.4f}',
f'{asimetria:.4f}', f'{curtosis:.4f}',
f'{len(target)}', f'{len(outliers)}'
]
})
print('\nRESUMEN INTEGRADO DE TODAS LAS METRICAS — target')
print('=' * 50)
print(resumen.to_string(index=False))
print('=' * 50)
Resumen estadistico de todas las variables:
count mean std min 25% 50% 75% max
age 442.0 -0.0000 0.0476 -0.1072 -0.0373 0.0054 0.0381 0.1107
sex 442.0 0.0000 0.0476 -0.0446 -0.0446 -0.0446 0.0507 0.0507
bmi 442.0 -0.0000 0.0476 -0.0903 -0.0342 -0.0073 0.0312 0.1706
bp 442.0 -0.0000 0.0476 -0.1124 -0.0367 -0.0057 0.0356 0.1320
s1 442.0 -0.0000 0.0476 -0.1268 -0.0342 -0.0043 0.0284 0.1539
s2 442.0 0.0000 0.0476 -0.1156 -0.0304 -0.0038 0.0298 0.1988
s3 442.0 -0.0000 0.0476 -0.1023 -0.0351 -0.0066 0.0293 0.1812
s4 442.0 -0.0000 0.0476 -0.0764 -0.0395 -0.0026 0.0343 0.1852
s5 442.0 0.0000 0.0476 -0.1261 -0.0332 -0.0019 0.0324 0.1336
s6 442.0 0.0000 0.0476 -0.1378 -0.0332 -0.0011 0.0279 0.1356
target 442.0 152.1335 77.0930 25.0000 87.0000 140.5000 211.5000 346.0000
RESUMEN INTEGRADO DE TODAS LAS METRICAS — target
==================================================
Metrica Valor
Media aritmetica 152.1335
Mediana 140.5000
Moda 72.0000
Media geometrica 131.8049
Media armonica 112.1427
Q1 (P25) 87.0000
Q2 (P50) 140.5000
Q3 (P75) 211.5000
IQR 124.5000
Percentil 10 60.0000
Percentil 90 265.0000
Minimo 25.0000
Maximo 346.0000
Rango 321.0000
Varianza (muestral) 5943.3313
Desviacion estandar 77.0930
Coef. de variacion (%) 50.67%
Error estandar 3.6669
Asimetria (Skewness) 0.4391
Curtosis (Fisher) -0.8866
N observaciones 442
Outliers (Tukey) 0
==================================================
11. Visualizaciones¶
Boschetti y Massaron (2018, pp. 282-316) y Fuentes (2018, pp. 121-129) coinciden en que la visualizacion no es un complemento estetico, sino una herramienta de analisis que revela patrones invisibles en las tablas numericas.
11.1 Histograma con KDE y medidas de tendencia central¶
# ============================================================
# GRAFICO 1: Histograma con Estimacion de Densidad de Kernel (KDE)
#
# El histograma muestra la distribucion de frecuencias de target.
# La curva KDE (Kernel Density Estimation) es una estimacion
# continua de la funcion de densidad de probabilidad.
# Las lineas verticales muestran la posicion de media, mediana
# y moda, permitiendo observar visualmente la simetria o asimetria.
# (Boschetti y Massaron, 2018, pp. 299-300; Cady, 2020, p. 63)
# ============================================================
fig, ax = plt.subplots(figsize=(10, 5))
sns.histplot(target, kde=True, bins=20, color='steelblue',
edgecolor='white', alpha=0.7, ax=ax)
ax.axvline(media, color='crimson', linestyle='--', linewidth=2,
label=f'Media = {media:.1f}')
ax.axvline(mediana, color='darkorange', linestyle='-', linewidth=2,
label=f'Mediana = {mediana:.1f}')
ax.axvline(moda, color='seagreen', linestyle=':', linewidth=2,
label=f'Moda = {moda:.1f}')
ax.set_title('Grafico 1. Distribucion de la Progresion de Diabetes (target)\ncon Medidas de Posicion Central', fontsize=12)
ax.set_xlabel('Progresion de la enfermedad al siguiente anyo')
ax.set_ylabel('Frecuencia')
ax.legend()
plt.tight_layout()
plt.savefig('grafico_histograma.png', dpi=150, bbox_inches='tight')
plt.show()
print('La posicion relativa de media y mediana confirma la asimetria calculada numericamente.')
La posicion relativa de media y mediana confirma la asimetria calculada numericamente.
11.2 Diagrama de caja (Boxplot)¶
# ============================================================
# GRAFICO 2: Boxplot (Diagrama de Caja y Bigotes)
#
# El boxplot resume visualmente los cuartiles, el IQR y los
# valores atipicos en un solo grafico.
# Componentes:
# - Caja: de Q1 a Q3 (contiene el 50% central de los datos)
# - Linea interior: mediana (Q2)
# - Bigotes: se extienden hasta 1.5 * IQR desde Q1 y Q3
# - Puntos individuales: outliers que superan los limites
# (Cady, 2020, pp. 65-68; Boschetti y Massaron, 2018, p. 297)
# ============================================================
fig, ax = plt.subplots(figsize=(10, 4))
ax.boxplot(target, vert=False, patch_artist=True,
boxprops=dict(facecolor='steelblue', alpha=0.5),
medianprops=dict(color='crimson', linewidth=2),
whiskerprops=dict(color='gray'),
flierprops=dict(marker='o', color='darkred', alpha=0.4, markersize=5))
ax.axvline(Q1, color='navy', linestyle='--', alpha=0.4, label=f'Q1 = {Q1:.1f}')
ax.axvline(Q3, color='purple', linestyle='--', alpha=0.4, label=f'Q3 = {Q3:.1f}')
ax.set_title('Grafico 2. Boxplot — Progresion de Diabetes (target)\nCuartiles, IQR y Valores Atipicos', fontsize=12)
ax.set_xlabel('Progresion de la enfermedad al siguiente anyo')
ax.legend(loc='lower right')
plt.tight_layout()
plt.savefig('grafico_boxplot.png', dpi=150, bbox_inches='tight')
plt.show()
print(f'Se detectaron {len(outliers)} valores atipicos por el metodo de Tukey.')
print('En contexto clinico, estos casos requieren revision individualizada.')
Se detectaron 0 valores atipicos por el metodo de Tukey. En contexto clinico, estos casos requieren revision individualizada.
11.3 Mapa de calor de correlaciones¶
# ============================================================
# GRAFICO 3: Mapa de calor de correlaciones entre variables
#
# La correlacion de Pearson mide la relacion lineal entre dos
# variables; sus valores van de -1 (inversa perfecta)
# a +1 (directa perfecta).
# El heatmap permite identificar rapidamente que variables
# tienen mayor relacion con la variable objetivo (target).
# (Cady, 2020, pp. 69-72; Boschetti y Massaron, 2018, p. 301)
# ============================================================
fig, ax = plt.subplots(figsize=(10, 8))
corr = df.corr()
mask = np.triu(np.ones_like(corr, dtype=bool)) # mostrar solo triangulo inferior
sns.heatmap(corr, mask=mask, annot=True, fmt='.2f',
cmap='coolwarm', center=0, vmin=-1, vmax=1,
linewidths=0.5, ax=ax)
ax.set_title('Grafico 3. Mapa de Calor — Correlaciones entre Variables\nDataset Diabetes', fontsize=12)
plt.tight_layout()
plt.savefig('grafico_correlaciones.png', dpi=150, bbox_inches='tight')
plt.show()
print('Las variables s5 (log trigliceridos) y bmi muestran mayor correlacion con target.')
print('Esta informacion guiara la seleccion de variables en la regresion lineal (semana 7).')
Las variables s5 (log trigliceridos) y bmi muestran mayor correlacion con target. Esta informacion guiara la seleccion de variables en la regresion lineal (semana 7).
11.4 Diagrama de dispersion: BMI vs Target¶
# ============================================================
# GRAFICO 4: Diagrama de dispersion con linea de tendencia
#
# Muestra la relacion entre la variable bmi (IMC) y la
# variable objetivo target. Se agrega una linea de regresion
# lineal simple calculada con scipy.stats.linregress
# para anticipar el tema de la semana 7.
# (Cady, 2020, pp. 73-76; Boschetti y Massaron, 2018, p. 288)
# ============================================================
fig, ax = plt.subplots(figsize=(9, 5))
ax.scatter(df['bmi'], df['target'],
alpha=0.4, color='steelblue', edgecolors='white', s=35)
m, b, r_val, p_val, se = stats.linregress(df['bmi'], df['target'])
x_line = np.linspace(df['bmi'].min(), df['bmi'].max(), 100)
ax.plot(x_line, m * x_line + b, color='crimson', linewidth=2,
label=f'Linea de tendencia (r = {r_val:.3f})')
ax.set_title('Grafico 4. BMI vs Progresion de Diabetes\nRelacion y Tendencia Lineal', fontsize=12)
ax.set_xlabel('Indice de Masa Corporal (BMI) — estandarizado')
ax.set_ylabel('Progresion de la enfermedad (target)')
ax.legend()
plt.tight_layout()
plt.savefig('grafico_scatter.png', dpi=150, bbox_inches='tight')
plt.show()
print(f'Correlacion de Pearson r = {r_val:.3f}: relacion positiva {"moderada" if abs(r_val)<0.6 else "alta"}.')
print('A mayor IMC, mayor tiende a ser la progresion de la enfermedad.')
Correlacion de Pearson r = 0.586: relacion positiva moderada. A mayor IMC, mayor tiende a ser la progresion de la enfermedad.
11.5 Grafico de barras de frecuencias absolutas¶
# ============================================================
# GRAFICO 5: Frecuencias absolutas por intervalo
#
# Representa visualmente la tabla de frecuencias calculada
# anteriormente. Permite identificar los intervalos con mayor
# concentracion de pacientes.
# (Boschetti y Massaron, 2018, pp. 291-292)
# ============================================================
fig, ax = plt.subplots(figsize=(10, 5))
barras = ax.bar(tabla_freq['Intervalo'], tabla_freq['Frec. Absoluta'],
color='steelblue', alpha=0.7, edgecolor='white')
ax.bar_label(barras, fmt='%d', padding=2, fontsize=9)
ax.set_title('Grafico 5. Frecuencias Absolutas por Intervalo\nProgresion de Diabetes (target)', fontsize=12)
ax.set_xlabel('Intervalo de progresion')
ax.set_ylabel('Numero de pacientes')
plt.xticks(rotation=30, ha='right')
plt.tight_layout()
plt.savefig('grafico_frecuencias.png', dpi=150, bbox_inches='tight')
plt.show()
idx_max = tabla_freq['Frec. Absoluta'].idxmax()
print(f'El intervalo con mayor concentracion es: {tabla_freq.loc[idx_max, "Intervalo"]}'
f' con {tabla_freq.loc[idx_max, "Frec. Absoluta"]} pacientes.')
El intervalo con mayor concentracion es: [65 - 105) con 101 pacientes.
11.6 Panel comparativo de distribuciones¶
# ============================================================
# GRAFICO 6: Panel comparativo — distribuciones de variables clave
#
# Muestra el histograma de las 5 variables mas relevantes
# (age, bmi, bp, s5, target) en una cuadricula unica.
# Las lineas rojas indican la media y las naranjas la mediana.
# Permite detectar visualmente simetria o asimetria en cada
# variable sin necesidad de calculos adicionales.
# (Boschetti y Massaron, 2018, pp. 296-300; Fuentes, 2018, p. 126)
# ============================================================
variables = ['age', 'bmi', 'bp', 's5', 'target']
fig, axes = plt.subplots(1, len(variables), figsize=(16, 4))
fig.suptitle('Grafico 6. Distribucion de Variables Seleccionadas\nLinea roja = Media | Linea naranja = Mediana',
fontsize=11, y=1.02)
for i, var in enumerate(variables):
axes[i].hist(df[var], bins=15, color='steelblue', alpha=0.7, edgecolor='white')
axes[i].axvline(df[var].mean(), color='crimson', linestyle='--', linewidth=1.2)
axes[i].axvline(df[var].median(), color='darkorange', linestyle='-', linewidth=1.2)
axes[i].set_title(var, fontsize=11)
plt.tight_layout()
plt.savefig('grafico_panel.png', dpi=150, bbox_inches='tight')
plt.show()
print('El panel permite comparar la forma de la distribucion entre variables.')
print('La variable target muestra mayor dispersion relativa que las variables estandarizadas.')
El panel permite comparar la forma de la distribucion entre variables. La variable target muestra mayor dispersion relativa que las variables estandarizadas.
12. Conclusiones¶
El analisis estadistico del Dataset de Diabetes arrojo cinco reflexiones que van mas alla del calculo puntual.
Primera. El coeficiente de variacion de la variable progresion supera el 50 por ciento, lo que indica una heterogeneidad marcada entre pacientes. Hablar del paciente promedio oculta realidades criticas que necesitan atencion diferenciada. El mismo problema aparece en el sistema judicial cuando se promedia el tiempo de resolucion de tutelas: el promedio esconde los casos urgentes.
Segunda. La visualizacion no es un adorno, es analisis. El boxplot revelo outliers que la tabla de frecuencias solo insinuaba. El mapa de calor confirmo que el IMC y los trigliceridos sericos son las variables con mayor relacion con la progresion de la enfermedad; ese hallazgo guiara la seleccion de predictores para la regresion lineal de la semana 7 (Boschetti y Massaron, 2018, pp. 296-302).
Tercera. La diferencia entre medias aritmetica, geometrica y armonica no es un ejercicio matematico abstracto. En datos clinicos reales donde los valores no se distribuyen de forma lineal, la eleccion de la media adecuada puede cambiar los resultados de un analisis de manera significativa (Cady, 2020, pp. 63-65).
Cuarta. Los outliers detectados no son necesariamente errores. Como discutimos en clase, los datos atipicos en datasets humanos pueden representar casos excepcionales con comorbilidades o tratamientos poco frecuentes. La decision de eliminarlos, corregirlos o conservarlos es estadistica y etica al mismo tiempo (Cady, 2020, pp. 58-60).
Quinta. Python democratiza el analisis estadistico. Lo que antes requeria software especializado y semanas de trabajo, hoy se ejecuta en minutos con NumPy, Pandas, SciPy y Seaborn. La barrera ya no es tecnica; es conceptual. Por eso el docente insiste en entender la estadistica antes de escribir una sola linea de codigo (Fuentes, 2018, pp. 121-123).
13. Referencias (Normas APA, 7.a edicion)¶
Boschetti, A., y Massaron, L. (2018). Python data science essentials: A practitioner's guide covering essential data science principles, tools, and techniques (pp. 282-316). Packt Publishing.
Cady, F. (2020). Data science: The executive summary — a technical book for non-technical professionals (pp. 55-95). John Wiley & Sons.
Efron, B., Hastie, T., Johnstone, I., y Tibshirani, R. (2004). Least angle regression. Annals of Statistics, 32(2), 407-499. https://doi.org/10.1214/009053604000000067
Fuentes, A. (2018). Become a Python data analyst: Perform exploratory data analysis and gain insight into scientific computing using Python (pp. 121-137). Packt Publishing.
Pedregosa, F., Varoquaux, G., Gramfort, A., Michel, V., Thirion, B., Grisel, O., Blondel, M., Prettenhofer, P., Weiss, R., Dubourg, V., Vanderplas, J., Passos, A., Cournapeau, D., Brucher, M., Perrot, M., y Duchesnay, E. (2011). Scikit-learn: Machine learning in Python. Journal of Machine Learning Research, 12, 2825-2830. https://jmlr.org/papers/v12/pedregosa11a.html