Autor: Fernando

  • Correlación: Cómo Entender la Relación entre Variables

    En este articulo se explora la correlación entre diferentes factores y se estima hasta qué punto son confiables sus relaciones. Además, aborda sobre los diferentes tipos de análisis que podemos realizar para descubrir la relación entre los datos: análisis univariado, bivariado y multivariado.

    Cualquier conjunto de datos que queramos analizar tendrá diferentes campos (columnas) con múltiples observaciones (filas). Estas variables suelen estar relacionadas entre sí, ya que se recopilan del mismo fenómeno. Un campo puede influir o no sobre otro; para entenderlo, necesitamos detectar las dependencias existentes entre variables.

    La fuerza de la relación entre dos campos de un conjunto de datos se llama correlación, y se representa con un número entre -1 y 1.

    En otras palabras, la correlación es una técnica estadística que mide y describe cómo se relacionan y varían juntas dos variables. Nos permite responder preguntas como:

    • ¿Cómo cambia una variable con respecto a otra?
    • Si cambia, ¿en qué grado o fuerza?
    • ¿Podemos predecir una a partir de la otra?

    Por ejemplo: la altura y el peso suelen estar relacionados. Las personas más altas tienden a pesar más que las más bajas. Si encontramos una persona más alta que el promedio, es razonable esperar que también pese más que el promedio.

    Qué es el Coeficiente de Correlación

    La correlación nos indica cómo cambian las variables juntas, ya sea en la misma dirección o en direcciones opuestas, y la fuerza de esa relación. El coeficiente de correlación de Pearson \(ρ\) o \(r\) mide esta relación y se calcula como:

    $$r_{xy} = \frac{\text{cov}(x, y)}{\sigma_x , \sigma_y}$$

    donde:

    • \( \text{cov}(x, y)\) es la covarianza entre las variables,
    • \( \sigma_x \) y \( \sigma_y \) son sus desviaciones estándar.

    El valor de ( r ) varía entre -1 y +1:

    Valor de rTipo de correlaciónInterpretación
    +1Perfecta positivaAmbas variables crecen juntas
    0NulaNo hay relación lineal
    -1Perfecta negativaUna crece mientras la otra disminuye

    Valores cercanos a |1| indican una relación fuerte, mientras que los cercanos a 0 indican una relación débil o inexistente.

    Visualización: Diagramas de Dispersión

    Los diagramas de dispersión son herramientas visuales clave para observar la correlación entre dos variables.

    A continuación, veremos ejemplos con Python.

    import matplotlib.pyplot as plt
    import numpy as np
    
    # Generar datos simulados
    x = np.linspace(1, 10, 10)
    y_pos = 2.5 * x + np.random.normal(0, 1, 10)      # correlación positiva
    y_neg = -2.5 * x + np.random.normal(0, 1, 10)     # correlación negativa
    y_none = np.random.normal(5, 5, 10)               # sin correlación
    
    # Crear figuras
    fig, axs = plt.subplots(1, 3, figsize=(12, 4))
    
    axs[0].scatter(x, y_pos, color='green')
    axs[0].set_title('Correlación Positiva')
    
    axs[1].scatter(x, y_neg, color='red')
    axs[1].set_title('Correlación Negativa')
    
    axs[2].scatter(x, y_none, color='gray')
    axs[2].set_title('Sin Correlación')
    
    for ax in axs:
        ax.set_xlabel('Variable X')
        ax.set_ylabel('Variable Y')
        ax.grid(True)
    
    plt.tight_layout()
    plt.show()

    Cuanto más se acerquen los puntos a una línea recta, mayor será la correlación.
    Si los puntos están dispersos sin formar ningún patrón, la correlación es baja o inexistente.

    Correlación No Implica Causalidad

    Una frase muy importante en estadística es:

    La correlación no implica causalidad.”

    Esto significa que dos cosas pueden estar relacionadas sin que una cause la otra.
    Por ejemplo:

    • En invierno la gente compra más sopa caliente. Pero el frío no causa que la gente gaste más dinero; ambos fenómenos están relacionados por un tercer factor (la estación del año).
    • Las ventas de helado y los homicidios aumentan simultáneamente durante el verano.
      No significa que comer helado cause homicidios; ambos están correlacionados por la temperatura, que influye en ambos comportamientos.

    Por tanto, una correlación fuerte no garantiza una relación de causa-efecto. Antes de sacar conclusiones, es crucial analizar los factores subyacentes.

    Análisis Bivariado

    El análisis bivariado estudia la relación entre dos variables. Se usa para determinar si existe una relación y qué tipo de relación hay (positiva, negativa o nula). Por ejemplo, analicemos la relación entre el dinero invertido en publicidad y las ventas obtenidas:

    Usando Numpy y Scipy:

    import numpy as np
    from scipy import stats
    import matplotlib.pyplot as plt
    
    # Datos ficticios
    publicidad = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
    ventas = np.array([10, 13, 19, 23, 26, 33, 38, 41, 47])
    
    # Calcular coeficiente de correlación con Numpy
    correlacion = np.corrcoef(publicidad, ventas)[0, 1]
    print(f"Coeficiente de correlación de Pearson: {correlacion:.3f}")
    
    # Calcular coeficiente de correlación con Scipy
    corr = stats.pearsonr(publicidad, ventas)
    print("Correlación:", corr[0])
    
    # Graficar
    plt.scatter(publicidad, ventas, color='blue', label='Datos')
    m, b = np.polyfit(publicidad, ventas, 1)
    plt.plot(publicidad, m*publicidad + b, color='red', label='Línea de mejor ajuste')
    plt.xlabel("Dólares en publicidad")
    plt.ylabel("Ventas")
    plt.title("Análisis Bivariado: Publicidad vs Ventas")
    plt.legend()
    plt.grid(True)
    plt.show()

    Salida:

    Coeficiente de correlación de Pearson: 0.997
    Correlación: 0.9973743231694302

    Interpretación:
    Si el coeficiente de correlación \( r \) es cercano a 1, existe una relación positiva fuerte, lo que sugiere que al aumentar la inversión publicitaria, las ventas también aumentan.

    Análisis Multivariado

    El análisis multivariado examina tres o más variables al mismo tiempo, buscando relaciones más complejas. Se utiliza cuando queremos entender cómo varias variables interactúan entre sí para predecir un resultado.

    Ejemplo: predecir el precio de una casa según tamaño, ubicación y número de habitaciones.

    import pandas as pd
    import seaborn as sns
    import matplotlib.pyplot as plt
    from sklearn.linear_model import LinearRegression
    import numpy as np
    
    data = pd.DataFrame({
        'tamaño_m2': [45, 55, 65, 75, 85, 95, 105, 115],
        'habitaciones': [1, 2, 2, 3, 3, 3, 4, 4],
        'ubicacion': [5, 4, 3, 2, 4, 3, 2, 1],  # zonas más caras no siempre coinciden con mayor tamaño
        'precio': [160000, 170000, 185000, 190000, 210000, 220000, 240000, 230000]
    })
    
    # Variables independientes y dependiente
    X = data[['tamaño_m2', 'habitaciones', 'ubicacion']]
    y = data['precio']
    
    # Crear y entrenar el modelo
    modelo = LinearRegression()
    modelo.fit(X, y)
    
    # Mostrar resultados
    print("Coeficientes:", modelo.coef_)
    print("Intercepto:", modelo.intercept_)
    
    # --- Gráfico de correlaciones ---
    plt.figure(figsize=(8, 6))
    sns.heatmap(data.corr(), annot=True, cmap='coolwarm', fmt=".2f", linewidths=0.5)
    plt.title("Mapa de calor de correlaciones", fontsize=14)
    plt.show()
    Coeficientes: [ 1800.  22000. -9000.]
    Intercepto: 11000.0

    Interpretación:

    • Coeficiente de tamaño_m2: 1800
      ➜ Por cada metro cuadrado adicional, el precio sube 1,800 €, manteniendo las demás variables constantes.
    • Coeficiente de habitaciones: 22000
      ➜ Añadir una habitación aumenta el precio promedio en 22,000 €, suponiendo mismo tamaño y ubicación.
    • Coeficiente de ubicacion: -9000
      ➜ En este ejemplo, los valores de ubicación están codificados de forma que un número menor representa una zona mejor.
      Por eso el coeficiente es negativo: al bajar el número (mejor ubicación), aumenta el precio.
    • Intercepto: 11,000
      ➜ Es el valor base del modelo cuando todas las variables valen 0 (solo tiene sentido teórico, no real).

    El análisis multivariado permite estimar el efecto combinado de múltiples variables y mejorar la precisión de las predicciones.

    Limitaciones de la Correlación

    La correlación solo mide relaciones lineales. Puede ser engañosa cuando la relación es curvilínea o no lineal. Por ejemplo, los siguientes diagramas de dispersión muestran pares de variables con correlaciones cercanas a cero:

    • En uno de ellos, la relación es perfectamente horizontal (pendiente = 0).
    • En los demás, las relaciones son no lineales (curvas, cuadráticas, circulares, etc.).

    En estos casos, la correlación no detecta la relación real, porque una línea recta no puede describir la forma del patrón.

    Explorando la covarianza

    Más allá de visualizar relaciones, también podemos utilizar estadísticas resumidas para cuantificar la fuerza de ciertas asociaciones. La covarianza es una estadística resumida que describe la fuerza de una relación lineal.

    La covarianza puede variar desde infinito negativo hasta infinito positivo. Una covarianza positiva indica que un valor mayor de una variable está asociado con un valor mayor de la otra. Una covarianza negativa indica que un valor mayor de una variable está asociado con un valor menor de la otra. Una covarianza de 0 indica que no hay relación lineal. Aquí hay unos ejemplos:

    Para calcular la covarianza, podemos usar la función cov() de NumPy, que produce una matriz de covarianza para dos o más variables . Una matriz de covarianza para dos variables se parece a esto:

     Variable 1Variable 2
    Variable 1varianza (Variable 1)covarianza
    Variable 2covarianzavarianza (Variable 2)

    En Python, podemos calcular esta matriz de la siguiente manera:

    import pandas as pd
    import numpy as np
    import seaborn as sns
    import matplotlib.pyplot as plt
    
    # Datos simulados de viviendas
    data = pd.DataFrame({
        'tamaño_m2': [45, 55, 65, 75, 85, 95, 105, 115],
        'habitaciones': [1, 2, 2, 3, 3, 3, 4, 4],
        'ubicacion': [5, 4, 3, 2, 4, 3, 2, 1],  # zonas más caras no siempre coinciden con mayor tamaño
        'precio': [160000, 170000, 185000, 190000, 210000, 220000, 240000, 230000]
    })
    
    # --- 1️⃣ Cálculo manual y con NumPy ---
    cov_matrix = np.cov(data['tamaño_m2'], data['precio'])
    cov_tamaño_precio = cov_matrix[0, 1]
    
    print("Matriz de Covarianza:\n", cov_matrix)
    print("\nCovarianza entre tamaño_m2 y precio:", round(cov_tamaño_precio, 2))

    Salida:

    Matriz de Covarianza:
    [[ 616.07142857 5687.5       ]
     [5687.5       53839285.71428572]]
    
    Covarianza entre tamaño_m2 y precio: 5687.5

    Interpretación

    • El valor 5 687.5 es positivo, lo que significa que cuando el tamaño aumenta, el precio también tiende a aumentar.
    • Si fuera negativo, indicaría que los valores mayores de una variable se asocian con valores menores de la otra.
    • Si fuera cercano a 0, implicaría que no hay una relación lineal clara entre tamaño y precio.

    La magnitud (qué tan grande es el número) depende de las unidades de medida. Por eso, la covarianza no es directamente comparable entre conjuntos de datos distintos. Para una medida normalizada e interpretable, se usa la correlación de Pearson, que va de -1 a +1.

  • Exploración de Datos con Estadística Descriptiva y Visualización

    ¿Qué cubre el análisis de datos exploratorios avanzados?

    • Calcular la varianza de una variable.
    • Evaluar la distribución de los datos.
    • Informar sobre cuartiles, cuantiles y rango intercuartil.
    • Explorar datos categóricos.
    • Transformar los datos para satisfacer tus necesidades.

    Varianza

    Calcular la media, mediana y moda es un buen comienzo para comprender la forma general de un conjunto de datos. Pero esas tres estadísticas solo cuentan parte de la historia.

    Considera los dos conjuntos siguientes:

    dataset_one = [-4, -2, 0, 2, 4]
    dataset_two = [-400, -200, 0, 200, 400]

    Ambos tienen la misma media y mediana (0), pero claramente no representan la misma dispersión. Ahí entra en juego la varianza, que describe qué tan dispersos están los datos.

    Distancia desde la media

    Intuitivamente, queremos que la varianza sea mayor cuando los datos están más dispersos y menor cuando están más concentrados. Una primera idea sería usar el rango, pero solo considera los extremos.

    En cambio, podemos medir cuánto se aleja cada punto de la media:

    $$\text{diferencia} = X – \mu$$

    Donde \( X \) es un punto de datos y \( \mu \) la media.

    Promedio de las distancias

    Podemos combinar las diferencias en una sola medida tomando su promedio. Sin embargo, si los valores por encima y por debajo de la media se cancelan (por ejemplo, [-5, 5]), el promedio sería 0, aunque los datos estén claramente dispersos.

    Cuadrar las diferencias

    Para evitar la cancelación, elevamos al cuadrado las diferencias:

    $$\text{diferencia} = (X – \mu)^2$$

    De este modo, los valores negativos desaparecen y las grandes desviaciones pesan más.

    La varianza \( \sigma^2 \) se define entonces como:

    $$\sigma^2 = \frac{\sum_{i=1}^n (x_i – \mu)^2}{n}$$

    Varianza en Python

    import numpy as np
    
    dataset = [3, 5, -2, 49, 10]
    variance = np.var(dataset)
    print(f"Varianza: {variance:.2f}")

    Salida:

    Varianza: 328.56

    La varianza no se interpreta directamente, sin tener en cuenta la escala de los datos. Esta crece con la magnitud de los valores porque está en unidades al cuadrado. Por eso, comparar una varianza de 328.56 en dos contextos distintos (media = 13 o media = 1200) no tiene sentido absoluto. En el primer caso, las desviaciones son grandes respecto a la media y en el segundo, son minúsculas.

    Entonces:

    La varianza no es una medida relativa, y solo tiene valor comparativo si las variables están en la misma escala.

    Desviación estándar

    La varianza tiene un inconveniente: sus unidades están al cuadrado como ya vimos anteriormente. Por eso usamos la desviación estándar, que devuelve las unidades originales:

    $$\sigma = \sqrt{\sigma^2}$$

    Desviación estándar con NumPy

    import numpy as np
    
    dataset = [4, 8, 15, 16, 23, 42]
    standard_deviation = np.std(dataset)
    print(f"Desviación estándar: {standard_deviation:.2f}")

    Salida:

    Desviación estándar: 12.32

    Interpretación práctica

    La desviación estándar permite interpretar cuán inusual es un valor.  Al encontrar el número de desviaciones estándar que un punto de datos está alejado de la media, podemos comenzar a investigar qué tan inusual es realmente ese punto de datos. 

    • ~68% de los datos están dentro de de la media.
    • ~95% dentro de .
    • ~99.7% dentro de .

    Si un punto se encuentra a más de tres desviaciones estándar, es un valor atípico.

    Describiendo un histograma

    Media y Mediana

    Ambas indican el centro de los datos. En distribuciones simétricas, suelen coincidir.

    Dispersión (Spread)

    Se describe con los valores mínimo y máximo, tomados con la media y la mediana, comienzan a indicar la forma del conjunto de datos subyacente.

    Sesgo (Skewness)

    • Simétrico: la media ≈ mediana.
    • Sesgo a la derecha: cola larga hacia la derecha, media > mediana.
    • Sesgo a la izquierda: cola larga hacia la izquierda, media < mediana.

    Modalidad

    La modalidad describe el número de picos en un conjunto de datos. 

    • Unimodal: un solo pico.
    • Bimodal o multimodal: varios picos.
    • Uniforme: sin agrupaciones claras.

    Valores atípicos (Outliers)

    Son puntos lejanos al resto del conjunto de datos. Conviene investigarlos: pueden ser errores o indicios interesantes.

    Cuartiles

    Dividen los datos en cuatro partes iguales:

    • Q1: 25% inferior
    • Q2: 50% (la mediana)
    • Q3: 75% superior

    Ejemplo:

    import numpy as np
    
    dataset = [-108, 4, 8, 15, 16, 23, 42]
    
    q1 = np.quantile(dataset, 0.25)
    q2 = np.quantile(dataset, 0.50)
    q3 = np.quantile(dataset, 0.75)
    
    print(q1, q2, q3)

    Salida:

    4.0 15.0 23.0

    Cuantiles

    Los cuantiles dividen los datos en grupos de igual tamaño.
    Por ejemplo:

    • Deciles: 10 grupos
    • Percentiles: 100 grupos
    import numpy as np
    
    dataset = [5, 10, -20, 42, -9, 10]
    quantiles = np.quantile(dataset, [0.2, 0.4, 0.6, 0.8])
    print(quantiles)

    Salida:

    [-11.8  -3.6   9.2  23.6]

    Rango intercuartil (IQR)

    El rango intercuartil mide la amplitud del 50% central de los datos, entre el tercer cuartil (Q3) y el primer cuartil (Q1).

    $$IQR = Q3 – Q1$$

    Es más robusto ante valores atípicos que el rango total.

    from scipy.stats import iqr
    
    dataset = [4, 10, 38, 85, 193]
    interquartile_range = iqr(dataset)
    print(f"IQR: {interquartile_range}")
    IQR: 75.0

    Diagramas de caja (Boxplots)

    Los diagramas de caja son una de las formas más comunes de visualizar un conjunto de datos. Al igual que los histogramas , los diagramas de caja dan una idea de la tendencia central y la dispersión de los datos.

    Los boxplots resumen visualmente la distribución:

  • Del Modelo Lineal Simple a la Regresión por Mínimos Cuadrados

    El ajuste por mínimos cuadrados es uno de los pilares del análisis de datos. Nos permite encontrar patrones y relaciones entre variables incluso cuando los datos no son perfectos. La idea esencial es siempre la misma:

    Buscar los coeficientes que minimicen el error entre las observaciones reales y las predicciones del modelo.

    A partir de aquí, la regresión lineal se convierte en la base de modelos más complejos de machine learning, donde la idea de “ajustar” parámetros para minimizar errores sigue siendo el núcleo de todo el proceso.

    De los datos a la recta

    Imaginemos que tenemos dos variables, x y y, y sospechamos que están relacionadas de forma lineal. Por ejemplo:

    x = [1, 2, 3, 4, 5]
    y = [7, 11, 15, 19, 23]
    Código de la Grafica

    Código en Matplotlib

    import matplotlib.pyplot as plt
    
    # Datos
    x = [1, 2, 3, 4, 5]
    y = [7, 11, 15, 19, 23]
    
    # Crear gráfico de dispersión
    plt.scatter(x, y, color='blue', marker='o', label='Datos')
    
    # Etiquetas y título
    plt.title('Gráfico de dispersión: relación entre X y Y')
    plt.xlabel('X')
    plt.ylabel('Y')
    plt.grid(True)
    plt.legend()
    
    # Mostrar gráfico
    plt.show()

    El modelo lineal

    Si las variables son linealmente dependientes, podemos escribir:

    $$y = \beta_0 + \beta_1 x$$

    donde:

    • β₀ (beta cero) es el intercepto, el valor de y cuando x = 0.
    • β₁ (beta uno) es la pendiente, que indica cuánto cambia y por cada unidad de x.

    Nuestro objetivo es determinar estos coeficientes (β₀ y β₁) de manera que la recta se ajuste lo mejor posible a los datos.

    Representando el modelo como un sistema lineal

    Podemos escribir la ecuación anterior en forma matricial.
    Para cada observación de \(x\), formamos una fila en una matriz \(M\) que tiene dos columnas: una con los valores de \(x\) y otra con unos.

    $$M =\begin{bmatrix}1 & 1 \\ 2 & 1 \\ 3 & 1 \\ 4 & 1 \\ 5 & 1 \end{bmatrix} , \beta = \begin{bmatrix} \beta_1 \\ \beta_0 \end{bmatrix}$$

    Entonces el modelo se puede escribir como:

    $$y = M \cdot \beta$$

    donde \(y\) es el vector de observaciones reales.

    Si tenemos más ecuaciones que incógnitas (más datos que parámetros), se trata de un sistema sobredeterminado, y no habrá una solución exacta. En esos casos, buscamos una solución aproximada, aquella que minimiza los errores o residuos.

    Resolviendo con el método de los mínimos cuadrados

    La solución óptima en el sentido de mínimos cuadrados se obtiene resolviendo la ecuación normal:

    $$\hat{\beta} = (M^T M)^{-1} M^T y$$

    Aquí:

    • \( M^T \) es la traspuesta de \(M\).
    • \( (M^T M)^{-1} \) es su inversa.
    • \( \hat{\beta} \) son las estimaciones de los coeficientes.

    En el ejemplo de datos anteriores, este procedimiento nos da:

    $$\beta_0 = 3, \quad \beta_1 = 4$$

    por lo que la ecuación ajustada es:

    $$y = 3 + 4x$$

    Si probamos estos valores, obtenemos una coincidencia exacta con los datos: la relación es perfectamente lineal.

    Cuando los datos no son perfectamente lineales

    En la práctica, los datos reales rara vez se ajustan perfectamente a una línea.
    Supongamos que ahora tenemos un conjunto diferente:

    Código de la Grafica

    Código en Matplotlib

    import matplotlib.pyplot as plt
    
    # Datos
    x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    y = [8, 10, 14, 18, 21, 23, 26, 27, 29, 33]
    
    # Crear gráfico de dispersión
    plt.scatter(x, y, color='blue', marker='o', label='Datos')
    
    # Etiquetas y título
    plt.title('Gráfico de dispersión: relación entre X y Y')
    plt.xlabel('X')
    plt.ylabel('Y')
    plt.grid(True)
    plt.legend()
    
    # Mostrar gráfico
    plt.show()

    Vemos que no todos caen exactamente sobre una misma recta. Aun así, queremos una línea que represente la tendencia general: esa es la llamada línea de mejor ajuste (line of best fit).

    La idea de los residuos

    Cada punto tiene una pequeña distancia vertical hasta la recta estimada. Esa diferencia se llama residuo y se define como:

    $$\text{residuo}_i = y_i – \hat{y}_i$$

    donde \(\hat{y}_i\) es el valor predicho por el modelo. El método de mínimos cuadrados busca los parámetros β₀ y β₁ que minimicen la suma de los cuadrados de esos residuos:

    $$\text{min} \sum_{i=1}^{n} (y_i – \hat{y}_i)^2$$

    En forma desarrollada o explícita:

    $$\text{min:} (y_1 – \hat{y}_1)^2 + \cdots $$

    $$ + (y_n – \hat{y}_n)^2$$

    Al hacerlo, la recta resultante será aquella que “pasa más cerca” de todos los puntos en promedio.

    Interpretación visual

    • β₀ desplaza la recta hacia arriba o abajo.
    • β₁ modifica su inclinación.

    Podemos imaginar que “movemos” y “rotamos” la línea hasta que la suma de los residuos sea lo más pequeña posible. En ese punto, hemos encontrado la línea de mejor ajuste.

    Extensión a modelos polinomiales

    La misma lógica se puede aplicar cuando la relación no es lineal. Por ejemplo, si creemos que \(y \) depende de \(x²\), podemos ajustar un modelo cuadrático:

    $$y = \beta_0 + \beta_1 x + \beta_2 x^2$$

    En este caso, la matriz \(M \) tendrá tres columnas: una para \(x^2\), una para \(x\) y una para los unos.

    $$M = \begin{bmatrix} x_1^2 & x_1 & 1 \\ x_2^2 & x_2 & 1 \\ \vdots & \vdots & \vdots \\ x_n^2 & x_n & 1 \end{bmatrix}$$

    Y nuevamente, los coeficientes se obtienen con la misma fórmula general:

    $$\hat{\beta} = (M^T M)^{-1} M^T y$$

    Si aplicamos este método a un conjunto de datos donde la relación es cuadrática, obtendremos una curva que se adapta mucho mejor a los puntos observados que una simple línea.

    Generalización

    Esta metodología puede ampliarse para ajustar polinomios de grado superior o otros tipos de funciones (logarítmicas, exponenciales, etc.), siempre que podamos expresar el modelo en forma lineal respecto a los coeficientes β.

    Por ejemplo, para un polinomio cúbico \(y=\):

    $$\beta_0 + \beta_1 x + \cdots + \beta_3 x^3$$

    solo tendríamos que añadir una columna más a \(M\)con los valores de (x^3).

  • Regresión de Mínimos Cuadrados Ordinarios (OLS)

    Consideremos un sistema sobredeterminado, donde la matriz \( M \) no es cuadrada, sino rectangular: tiene dimensiones \(n \times p \), siendo \( n > p \). Esto ocurre, por ejemplo, cuando tenemos más observaciones que variables.

    Podemos imaginar un ejemplo sencillo:

    • \( x \) –> representa los precios de diferentes productos del supermercado.
    • \( M\) –> es una matriz que contiene la cantidad de cada producto que compraron distintas personas.
    • \( y\)–> es el vector del coste total de la compra de cada individuo.

    Hasta aquí, todo parece un sistema de ecuaciones lineales clásico: \( Mx = y \).
    Sin embargo, en la vida real los precios no son constantes: cambian entre tiendas, promociones o regiones. Así que incorporamos esa variabilidad aleatoria en el modelo.

    La idea probabilística

    Si cada individuo experimenta ligeras variaciones en los precios, no hay un único valor “verdadero” para cada producto. Por eso, nuestro objetivo no será encontrar un precio exacto, sino una estimación promedio de los precios:

    $$ \hat{x}$$

    donde el símbolo del “sombrero” \(ˆ\) indica que se trata de una estimación. De este modo, cada elemento de \( \hat{x} \) representa el precio medio estimado de un producto.

    Con esa estimación podemos obtener un coste total estimado multiplicando:

    $$\hat{y} = M \hat{x}$$

    Si nuestras estimaciones son buenas, entonces \(\hat{y} \) debería aproximarse lo más posible a los valores reales \( y \).

    Qué significa “lo más posible”

    Para medir qué tan cerca está nuestro resultado, podemos calcular la diferencia entre los valores reales y los estimados:

    $$y – \hat{y}$$

    y luego obtener su norma (la “distancia” entre ambos vectores). Nuestro objetivo es minimizar esa distancia. Este enfoque, de minimizar los errores cuadráticos, es justamente lo que hace la regresión OLS.

    Cómo funciona OLS

    En lugar de resolver directamente \( Mx = y \), multiplicamos ambos lados por la transpuesta de \( M \):

    $$M^T M x = M^T y$$

    Con esto obtenemos una matriz cuadrada \(p \times p\), que puede invertirse (si las columnas de \( M \) son linealmente independientes).

    De ahí obtenemos la fórmula del vector estimado:

    $$\hat{x} = (M^T M)^{-1} M^T y$$

    Este vector \( \hat{x} \)contiene los coeficientes de regresión, también llamados parámetros estimados.

    Comprobando la calidad del modelo

    Una vez tenemos \( \hat{x} \), podemos comparar las predicciones \( \hat{y} \) con los valores reales \( y \).
    Hay varias maneras de medir la calidad del ajuste:

    1. La norma del error: mide la magnitud de las diferencias \( y – \hat{y}\).
    2. El coeficiente de determinación \( R^2 \):
      Este valor, entre 0 y 1, indica qué proporción de la variación real de los datos está explicada por el modelo.
      • \( R^2 = 1 \): el modelo explica toda la variación (ajuste perfecto).
      • \(R^2 = 0\): el modelo no explica nada (mal ajuste).

    En esencia, \(R^2 \) compara cuánto mejoran nuestras predicciones respecto a usar solo el promedio de los datos.

    El concepto de residuo

    El residuo es la diferencia entre el valor real y el valor estimado para cada observación individual:

    $$\text{residuo}_i = y_i – \hat{y}_i$$

    Gráficamente, si representamos los puntos reales y los estimados, cada residuo es la distancia vertical entre ellos. Un buen modelo tendrá residuos pequeños y distribuidos al azar.

    Ejemplo: precios de supermercado

    Supongamos que tenemos 9 productos (manzanas, naranjas, pan, etc.) y los registros de compras de 450 personas. Cada persona pudo haber pagado precios ligeramente diferentes por los mismos artículos, dependiendo de la tienda o el día.

    • Si no hubiera variaciones (todos pagan el mismo precio), entonces \( \hat{y} = y \): el modelo reproduce exactamente los costes reales.
    • Si hay variaciones, los puntos estimados y los reales ya no coincidirán perfectamente, y aparecerán residuos.

    Aun así, la regresión OLS nos permite encontrar los promedios óptimos que minimizan los errores totales, proporcionando una estimación realista del comportamiento de compra.

    Paso 1: importar librerías y definir matrices

    import numpy as np
    
    # Matriz M: cantidades compradas (filas = personas, columnas = productos)
    M = np.array([
        [2, 3],   # persona 1: 2 manzanas, 3 naranjas
        [3, 5]    # persona 2: 3 manzanas, 5 naranjas
    ])
    
    # Vector y: total gastado por cada persona
    y = np.array([13, 21.6])

    Paso 2: aplicar la fórmula de OLS

    $$\hat{x} = (M^T M)^{-1} M^T y$$

    # Cálculo del estimador OLS
    x_hat = np.linalg.inv(M.T @ M) @ M.T @ y
    print("Estimaciones de precios:", x_hat)
    

    Salida esperada:

    Estimaciones de precios: [0.2 4.2]

    Esto indica que:

    • Precio estimado de una manzana ≈ $0.20
    • Precio estimado de una naranja ≈ $4.20

    Paso 3: calcular las predicciones y los residuos

    # Predicciones del modelo
    y_hat = M @ x_hat
    
    # Cálculo de los residuos
    residuos = y - y_hat
    
    print("Predicciones (ŷ):", y_hat)
    print("Residuos:", residuos)
    

    Salida esperada:

    Predicciones (ŷ): [13.  21.6]
    Residuos: [0. 0.]

    El modelo reproduce exactamente los valores observados, aunque —como vimos— los precios estimados no reflejan la realidad del sistema, porque el modelo no contempla variaciones individuales.

    Paso 4: medir la calidad del ajuste (R²)

    # Cálculo del coeficiente de determinación
    R2 = 1 - np.sum((y - y_hat)**2) / np.sum((y - np.mean(y))**2)
    print("Coeficiente R²:", R2)

    Salida esperada:

    Coeficiente R²: 1.0

    El modelo tiene un ajuste perfecto con solo dos observaciones, pero los parámetros no son realistas: este es un ejemplo ideal para entender que un buen ajuste no siempre significa un modelo correcto.

    Conclusión

    La regresión de mínimos cuadrados ordinarios (OLS) nos permite resolver sistemas lineales cuando los datos no encajan exactamente, buscando el mejor ajuste promedio posible.
    En este ejemplo, aunque el modelo predice perfectamente los costes totales, los parámetros estimados (los precios) son poco realistas porque los datos iniciales no cumplían las condiciones necesarias para una solución exacta.

    En la práctica, el OLS es una herramienta central en ciencia de datos: es la base de la regresión lineal, de muchos métodos de modelado predictivo y de análisis estadístico que permiten capturar relaciones entre variables reales y ruidosas.

  • Cuando la matriz no es cuadrada: el truco del transpuesto

    Imagina que tenemos una situación un poco diferente a la habitual. Supón que registramos el comportamiento de compra de varias personas en un supermercado. Tenemos los precios de los productos, los gastos totales de cada cliente, y una matriz que muestra cuántas unidades de cada producto compró cada uno.

    Cada persona compra distintas cantidades de unos pocos artículos —por ejemplo, tres productos diferentes—, y tenemos los datos de 100 clientes. Esto significa que nuestro número de filas (n = 100) es mucho mayor que el número de columnas (p = 3). En otras palabras, la matriz que representa esas compras ya no es cuadrada, sino rectangular.

    ¿Y cuál es el problema?
    Que las matrices rectangulares no tienen inversa, por lo que no podemos usar el método de “retroceso” (backsolving) que aplicábamos antes para resolver el sistema. En vez de rendirnos, vamos a usar un truco matemático muy útil: el transpuesto de la matriz.

    Qué significa transponer una matriz

    Transponer una matriz significa reflejar sus elementos respecto de la diagonal principal (la línea que va del vértice superior izquierdo al inferior derecho).
    Por ejemplo:

    • Si tienes un vector fila, su transpuesto será un vector columna.
    • Si tienes una matriz cuadrada, transponerla intercambia sus filas por columnas.
    • Si tienes una matriz rectangular de 3×2, su transpuesta será de 2×3.

    Una propiedad interesante es que el transpuesto del transpuesto te devuelve la matriz original.

    Qué ocurre al multiplicar una matriz por su transpuesta

    Supón que tienes una matriz \( M \) de tamaño \( n \times p \) (por ejemplo, 100 × 3). Si calculas el producto de su transpuesta por ella misma, es decir \( M^T \times M\), el resultado sí es una matriz cuadrada de tamaño \( p \times p \) (en este ejemplo, 3 × 3).
    Eso significa que podemos intentar invertirla.

    En resumen:

    • Si \( M \) es \(n \times p \),
    • entonces \( M^T \) es \(p \times n\),
    • y \( M^T M\) es \( p \times p \), una matriz cuadrada.

    Esto nos abre una puerta para resolver el sistema que antes parecía imposible.

    Aplicando el truco: resolver el sistema con el transpuesto

    En lugar de intentar resolver directamente \( Mx = y \) (lo cual no podemos hacer porque \(M\) no tiene inversa), multiplicamos ambos lados por \( M^T \):

    $$M^T Mx = M^T y$$

    Ahora, el sistema tiene una matriz cuadrada \(M^T M \).
    Si esta matriz tiene inversa, podemos calcular:

    $$x = (M^T M)^{-1} M^T y$$

    Y así obtenemos una solución para x.

    Cuándo existe esa inversa

    La clave está en la independencia lineal de las columnas de \(M\). Si las columnas son linealmente independientes (es decir, ninguna es combinación de las otras), entonces \( M^T M \) tendrá una inversa.

    Si no lo son —por ejemplo, si una columna es el doble de otra—, entonces \( M^T M \) no será invertible y este método no funcionará.

    Cómo hacerlo en Python

    En NumPy puedes obtener el transpuesto de una matriz simplemente con .T.
    Por ejemplo:

    import numpy as np
    
    M = np.array([[1, 2],
                  [3, 4],
                  [5, 6]])
    
    M_trans = M.T
    print(M_trans)

    El resultado será:

    [[1 3 5]
     [2 4 6]]

    Relación con la regresión lineal

    Lo que acabamos de hacer manualmente es, en esencia, una regresión lineal por mínimos cuadrados. En lugar de usar fórmulas estadísticas, usamos álgebra matricial para encontrar los coeficientes (precios) que mejor explican los datos observados (costes totales).

    En Python, este mismo procedimiento lo implementa la clase LinearRegression del paquete scikit-learn. Basta con:

    from sklearn.linear_model import LinearRegression
    
    modelo = LinearRegression(fit_intercept=False)
    modelo.fit(M, y)
    x_hat = modelo.coef_

    En resumen

    Cuando la matriz no es cuadrada, no podemos invertirla directamente. Pero si multiplicamos por su transpuesta, obtenemos una matriz cuadrada que sí puede tener inversa.
    Ese es el truco del transpuesto, y es la base de la regresión lineal y de muchos métodos de optimización en ciencia de datos.

  • Estadísticas Resumidas

    En el análisis de datos, especialmente cuando trabajamos con conjuntos de datos tabulares, es común que lo primero que queramos hacer sea “entender el terreno”: obtener una visión rápida de los patrones, la distribución y las características principales de las variables.
    A este proceso lo llamamos estadísticas resumidas (summary statistics), y constituye uno de los pilares del análisis exploratorio de datos (EDA, Exploratory Data Analysis).

    Estas estadísticas nos permiten responder preguntas básicas como:

    • ¿Qué tan centrados o dispersos están los datos?
    • ¿Existen valores extremos o atípicos?
    • ¿Cómo se distribuyen los valores?
    • ¿Qué categorías son más frecuentes?

    Estas herramientas —medias, dispersiones, cuartiles, gráficos y agrupaciones— nos permiten:

    • Preparar los datos para análisis más complejos.
    • Detectar errores o valores extremos.
    • Comprender patrones iniciales.

    Análisis Univariado: Explorando una Variable a la Vez

    El análisis univariado se enfoca en describir y entender una sola variable por vez. Es la forma más directa de comenzar el EDA y nos permite observar tendencias, detectar anomalías y entender el comportamiento general de los datos.

    Podemos dividirlo en dos grandes tipos:

    • Variables cuantitativas (numéricas)
    • Variables categóricas (de tipo texto o etiquetas)

    Veamos cómo se resumen y visualizan cada una.

    Variables Cuantitativas

    Medidas de Tendencia Central

    Las medidas de tendencia central buscan representar el valor “típico” o central de un conjunto de datos.

    • Media (promedio): la suma de todos los valores dividida por el número de observaciones. Es útil, pero sensible a valores atípicos.
    • Mediana: el valor que divide al conjunto en dos partes iguales. Menos afectada por outliers, representa mejor distribuciones sesgadas.
    • Moda: el valor más frecuente. Muy útil en datos categóricos o multimodales.
    • Media recortada: elimina un porcentaje de los valores más altos y bajos antes de calcular la media.
    df['column'].mean() # media
    df['column'].median() # mediana
    df['column'].mode() # Moda
    
    # Media recortada:
    from scipy.stats import trim_mean 
    trim_mean(df.column, proportiontocut=0.1)

    Medidas de Dispersión

    Describen cuánto varían los valores respecto al centro.

    • Rango: diferencia entre el valor máximo y el mínimo.
    • Varianza: mide la variabilidad cuadrática respecto a la media.
    • Desviación estándar: raíz cuadrada de la varianza; indica cuánto se alejan los datos, en promedio, de la media.
    • Desviación media absoluta (MAD): promedio de las diferencias absolutas respecto a la media.
    df['column'].max() - df['column'].min()  # rango
    df['column'].var()  # Varianza
    df['column'].std()  # Desviacion estandar
    (df.column - df.column.mean()).abs().mean()  # Desviación media absoluta

    Asimetría (Skewness) y Curtosis

    Estas métricas describen la forma de la distribución:

    • Asimetría (Skewness): indica si los datos están sesgados a la izquierda o derecha.
      • Sesgo positivo → cola larga a la derecha
      • Sesgo negativo → cola larga a la izquierda
    • Curtosis (Kurtosis): mide el peso de las colas de la distribución (presencia de valores extremos). df['column'].kurt()
      • Leptocúrtica: colas gruesas (muchos outliers)
      • Platicúrtica: colas delgadas
      • Mesocúrtica: similar a la normal
    df['column'].skew()  # Asimetría 
    df['column'].kurt()  # Curtosis

    Percentiles y Cuartiles

    Los percentiles indican el porcentaje de observaciones por debajo de un valor dado.
    Por ejemplo, el percentil 80 = 130 significa que el 80% de los valores son menores que 130.

    np.percentile(df['column'], 80)

    Los cuartiles dividen los datos en cuatro partes iguales:

    • Q1 (25%), Q2 (50% = mediana), Q3 (75%)

    El rango intercuartílico (IQR) se calcula como:

    IQR = Q3 - Q1

    y representa la dispersión central, resistente a outliers.

    Visualización: Histogramas y Boxplots

    Visualizar los datos es esencial para complementar las estadísticas numéricas.

    • Histograma: muestra la frecuencia de valores en intervalos (bins).
    sns.histplot(df['column'])
    • Boxplot (diagrama de caja): representa la mediana, los cuartiles y los valores atípicos.
    sns.boxplot(df['column'])

    Estos gráficos ayudan a detectar sesgos, simetrías y valores extremos de un vistazo.


    Variables Categóricas

    Cuando analizamos variables no numéricas (como “país”, “color” o “tipo de producto”), las estadísticas cambian.

    Frecuencias y Proporciones

    La herramienta básica es el conteo de valores:

    df['column'].value_counts()

    Y para ver proporciones:

    df['column'].value_counts(normalize=True)

    Estas proporciones nos ayudan a entender la distribución de categorías, especialmente cuando hay clases dominantes o poco representadas.

    Visualización

    • Gráficos de barras: ideales para mostrar frecuencias.
    sns.countplot(x='column', data=df)
    • Gráficos circulares (pie charts): útiles para proporciones, aunque menos precisos.

    Agrupación y Agregación de Datos

    En análisis exploratorios más profundos, necesitamos obtener estadísticas por grupo.
    Por ejemplo: ¿Cuál es el precio promedio por tipo de carrocería?

    La función groupby() de pandas permite dividir, aplicar y combinar fácilmente:

    df.groupby('body-style')['price'].mean()

    También podemos aplicar múltiples funciones de agregación:

    df.groupby(['body-style', 'drive-wheels']).agg({
        'height': 'min',
        'length': 'max',
        'price': 'mean'
    })

    Y definir agregaciones personalizadas con agg():

    df.agg({'length':['sum','min'], 'width':['max','min']})

    Este enfoque es esencial para crear tablas resumen, indicadores por categoría y comparativas entre grupos.

    Variables Categóricas Ordinales

    Algunas categorías tienen un orden lógico (por ejemplo: “bajo”, “medio”, “alto”).
    En estos casos, podemos convertirlas en variables de tipo category ordenadas para analizarlas numéricamente:

    order = ['Preschool', 'Primary', 'Secondary', 'College', 'Graduate']
    df['education'] = pd.Categorical(df['education'], categories=order, ordered=True)

    Esto permite calcular la mediana de la categoría:

    median_index = np.median(df['education'].cat.codes)
    order[int(median_index)]

    Importante:

    Aunque podemos asignar números, no debemos calcular medias si las distancias entre categorías no son uniformes.

  • Tratamiento de datos sesgados

    En el diseño de arquitecturas de Machine Learning, la calidad de las predicciones de un modelo no depende únicamente de la complejidad del algoritmo matemático seleccionado, sino de la forma geométrica de los datos que le suministramos.

    Muchos algoritmos fundamentales (como la Regresión Lineal, la Regresión Logística o las Redes Neuronales) asumen de manera implícita que las variables numéricas de entrada siguen una Distribución Normal (o Gaussiana). Sin embargo, en el mundo real, los datos de negocio suelen ser imperfectos y presentan sesgo o asimetría (skewness), acumulando la mayoría de sus registros en un extremo y extendiendo una larga cola en el sentido opuesto.

    En este artículo analítico, abordaremos en exclusiva las técnicas de ingeniería de características cuyo objetivo principal es reducir la asimetría de una distribución para aproximarla a una campana de Gauss.

    ¿Qué son los datos sesgados?

    Cuando un dataset presenta asimetría, la media, la mediana y la moda se separan, provocando que los modelos estadísticos tengan dificultades para aprender los patrones de forma equitativa. El escenario más común en analítica de negocio es la asimetría positiva (o sesgo a la derecha), donde la distribución presenta una cola alargada hacia los valores extremadamente altos. En una distribución normal, la media, la mediana y la moda coinciden, y la curva tiene forma de campana. Matemáticamente, se puede representar como:

    $$f(x) = \frac{1}{\sigma\sqrt{2\pi}} e^{-\frac{(x – \mu)^2}{2\sigma^2}}$$

    donde:

    • \( \mu \) es la media
    • \( \sigma \) la desviación estándar.

    Sin embargo, muchos conjuntos de datos reales, como ingresos, precios o número de visitas, presentan sesgo (skewness): una asimetría en la distribución.

    • Si la cola se extiende hacia la derecha, decimos que está sesgada positivamente.
    • Si se extiende hacia la izquierda, está sesgada negativamente.

    Por ejemplo, los ingresos de una población suelen estar sesgados a la derecha, porque hay muchas personas con ingresos bajos y pocas con ingresos muy altos.

    Reducir el sesgo mejora:

    • La precisión del modelo.
    • La interpretabilidad de los resultados.
    • La estabilidad numérica en el entrenamiento.

    Principales técnicas de transformación de datos

    A continuación, analizaremos las funciones matemáticas aplicadas en Data Science para comprimir las colas de las distribuciones y redistribuir los datos de forma simétrica.

    Transformación Logarítmica

    Es la técnica más extendida y utilizada en la industria. Consiste en aplicar el logaritmo natural a la variable predictora.

    $$y = \log(x)$$

    • Indicada para: Casos de asimetría positiva fuerte y distribuciones con colas extremadamente largas hacia la derecha.
    • Casos de uso típicos: Variables socioeconómicas o de comportamiento digital como ingresos, ventas acumuladas o tráfico web, donde unos pocos usuarios o registros presentan valores astronómicos en comparación con la media.
    • Limitación: Matemáticamente no está definida para valores menores o iguales a cero. Si existen ceros, suele aplicarse \(\log(x + 1)\) como variante técnica.

    Transformación de Raíz Cuadrada

    Una alternativa de compresión geométrica moderada.

    $$y = \sqrt{x}$$

    • Indicada para: Escenarios donde la asimetría positiva es moderada. Al ser menos agresiva que la función logarítmica, no deforma de manera tan drástica las distancias relativas.
    • Ventaja: Acepta directamente el valor cero en el dominio de la variable, haciéndola ideal para conteos.

    Transformación de Raíz Cúbica

    Una herramienta matemática versátil para la manipulación de espectros numéricos amplios.

    $$y = \sqrt[3]{x}$$

    • Indicada para: Distribuciones que contienen valores positivos, negativos y ceros simultáneamente, siempre que la asimetría no sea extrema. Al conservar el signo del input original, se permite estabilizar la varianza sin perder la naturaleza bidireccional del dato.

    Transformación Recíproca

    Una de las funciones de transmutación más agresivas en el arsenal estadístico.

    $$y = \frac{1}{x}$$

    • Indicada para: Distribuciones con una asimetría extremadamente severa y presencia de outliers de gran magnitud. Esta operación invierte el orden de magnitud, transformando los valores extremadamente grandes en valores cercanos a cero, logrando una compresión radical de la cola derecha.

    Transformaciones Avanzadas y Automatizadas

    En lugar de probar manualmente qué función matemática se adapta mejor a cada columna del dataset, la ciencia de datos moderna utiliza optimizadores algorítmicos que buscan el parámetro de transformación idóneo de manera automatizada.

    Transformación Box-Cox

    Es un método estadístico avanzado que parametriza la transformación mediante un valor de potencia llamado Lambda (\(\lambda\)). El algoritmo busca el \(\lambda\) óptimo que minimiza la asimetría de la variable resultante.

    $$y = \begin{cases} \frac{x^\lambda – 1}{\lambda} & \text{si } \lambda \neq 0 \\ \log(x) & \text{si } \lambda = 0 \end{cases}$$

    • Gran Limitación: Funciona única y exclusivamente con valores estrictamente positivos. Si la columna contiene un solo cero o un número negativo, el sistema fallará.

    Transformación Yeo-Johnson

    Considerada la evolución moderna del método Box-Cox. Modifica las ecuaciones para estabilizar las varianzas permitiendo que la potencia \(\lambda\) se calcule de forma segura sobre cualquier naturaleza numérica.

    • Ventajas de Producción: Es compatible con valores negativos y ceros. Debido a esta flexibilidad analítica, es una de las técnicas automatizadas más integradas en los pipelines de Machine Learning industriales (como los transformadores nativos de Scikit-Learn).

    Comparación de Transformaciones para Datos Sesgados

    TransformaciónIntensidadAdmite CerosAdmite Negativos
    LogarítmicaAltaNoNo
    Raíz CuadradaMediaNo
    Raíz CúbicaBaja
    Box-CoxAltaNoNo
    Yeo-JohnsonAlta

    Buenas prácticas

    1. Visualiza siempre tus datos antes y después de transformar.
    2. Mide la asimetría \( (\text{skewness})\) antes y después.
    3. No transformes por costumbre: hazlo solo si hay una razón estadística o del modelo.
    4. Guarda los parámetros de transformación si vas a aplicarlos en datos futuros (por ejemplo, en deploy de modelos).
    5. Considera también el escalado posterior (normalización o estandarización).

  • Manejo de Datos Faltantes

    Uno de los problemas más comunes en cualquier análisis de datos es la presencia de valores faltantes. No importa si trabajas con datos de clientes, de sensores, o de ventas: los huecos están ahí, casi siempre. Y si no los manejas bien, cualquier análisis que hagas puede llevarte a conclusiones incorrectas o sesgadas.

    Pero no te preocupes. Hay estrategias simples y efectivas para detectar, entender y manejar los datos faltantes de manera profesional. En este artículo aprenderás cómo hacerlo paso a paso.

    ¿Qué son los datos faltantes?

    Decimos que hay datos faltantes cuando una variable no tiene valor para una observación determinada. En la práctica, suelen aparecer como NULL, NaN, #N/A o simplemente celdas vacías.

    Por ejemplo, imagina que trabajas con los datos de ventas de varias tiendas de ropa y te encuentras con esto:

    StoreIDProductIDProductColorPrice
    A1Red20
    B3Blue18
    C1NULL20
    C2NULL25

    Aquí, las tiendas del grupo C no informaron el color del producto. Si no corriges este problema, cualquier análisis sobre los colores más vendidos será inexacto.

    Por qué es importante gestionar los datos faltantes

    Tener valores ausentes no solo significa un dataset incompleto. También puede distorsionar tus conclusiones. Por ejemplo, si intentas calcular la media de precios o la correlación entre variables sin tratarlos, obtendrás resultados falsos o sin sentido.

    Desde el punto de vista estadístico, manejar los datos faltantes aumenta el poder estadístico (la capacidad de detectar patrones reales en los datos) y reduce el riesgo de errores de interpretación.

    En resumen:

    • Mejora la precisión del análisis.
    • Evita conclusiones engañosas.
    • Permite conservar el tamaño de la muestra y su representatividad.

    Por qué faltan los datos

    Existen varias causas típicas:

    1. Errores o causas sistemáticas: El dato nunca se registró. Puede deberse a un descuido humano o a un fallo técnico.
    2. Privacidad o consentimiento: A veces los usuarios optan por no proporcionar ciertos datos, como su correo electrónico o edad.
    3. Pérdida o corrupción de información: Errores de conexión, fallos en la base de datos o interrupciones durante la carga de información pueden causar huecos.

    Tipos de datos faltantes

    No todos los datos faltantes son iguales. En ciencia de datos se clasifican en cuatro tipos:

    1. Estructuralmente faltantes (Expected Missing): Es normal que falten: por ejemplo, si alguien responde “no tengo asma”, es lógico que los campos sobre inhaladores estén vacíos.
    2. MCAR (Missing Completely at Random): Faltan al azar, sin ningún patrón. Es el caso ideal, aunque poco frecuente.
    3. MAR (Missing at Random): Faltan por alguna razón, pero dentro de ciertos grupos.
      Ejemplo: personas con un IMC alto tienden a no reportar su peso.
    4. MNAR (Missing Not at Random): Faltan por una razón directamente relacionada con el valor faltante. Por ejemplo, si los pacientes con presión arterial muy alta evitan hacerse la medición.

    Cómo identificar los datos faltantes

    1. Explora pequeñas muestras de datos:
      Visualiza las primeras o últimas filas para ver si hay celdas vacías.
    2. Usa funciones de resumen:
      En Python, data.isnull().sum() te mostrará cuántos valores faltan por columna.
    3. Compara recuentos:
      Si una columna tiene menos registros válidos que otras, probablemente tenga valores ausentes.

    Estrategias para manejar los datos faltantes

    1. Eliminación (borrar los datos faltantes)

    A veces la mejor solución es simplemente eliminar filas o columnas con datos faltantes.
    Pero cuidado: no siempre es seguro.

    Cuándo eliminar

    • Cuando los datos faltantes son pocos (menos del 5% del total).
    • Cuando los valores faltan al azar (MCAR o MAR).
    • Cuando los datos faltantes no afectan directamente al análisis principal.

    Cuándo no eliminar

    • Si perderías demasiadas observaciones (más del 20%).
    • Si los datos faltan por una razón estructural o sistemática.

    Tipos de eliminación

    Eliminación por lista:
    Borra toda la fila con cualquier dato faltante.

    data.dropna(inplace=True)

    Eliminación por pares:
    Solo elimina las filas que afecten a las variables que estás analizando.

    data.dropna(subset=['Height', 'Education'], inplace=True)

    Eliminación de variables:
    Si a una columna le falta más del 60% de los datos, puede ser mejor eliminarla por completo.


    2. Imputación (rellenar los huecos)

    Cuando los datos son valiosos y no conviene eliminarlos, podemos reemplazar los valores faltantes por otros estimados.

    Algunas estrategias:

    Media, mediana o moda

    Reemplaza los valores faltantes por el promedio, la mediana o el valor más común.

    data['Age'].fillna(data['Age'].mean(), inplace=True)

    Forward Fill (LOCF)

    Usa el valor anterior para completar el actual (útil en series temporales).

    data['Value'].ffill(inplace=True)

    Interpolación

    Calcula un valor intermedio entre los datos vecinos:

    data['Temperature'].interpolate(inplace=True)

    Modelos predictivos

    Utiliza algoritmos de Machine Learning (como regresión lineal o KNN) para estimar los valores faltantes en base a otras variables.

    Caso especial: datos faltantes en series temporales

    Cuando los datos se registran en el tiempo (como precios bursátiles o sensores IoT), los huecos pueden rellenarse con métodos temporales, como:

    • LOCF (Last Observation Carried Forward)
    • Interpolación lineal
    • Suavizado exponencial

    Por ejemplo:

    TimestampValue
    08:0112
    08:0213
    08:03Falta
    08:0416

    Podemos reemplazar el valor faltante (08:03) con el anterior (13) o con un promedio (14.5).

    Recomendaciones finales

    1. Entiende el contexto de tus datos.
      No todos los huecos significan error.
    2. Documenta tus decisiones.
      Explica por qué imputaste, eliminaste o dejaste un valor vacío.
    3. Evalúa el impacto.
      Comprueba cómo cambian tus resultados antes y después del tratamiento.

    En resumen

    EstrategiaCuándo usarlaRiesgo
    Eliminación por listaPocos valores faltantesPérdida de datos
    Eliminación por paresSolo faltan algunas variablesMínimo
    Imputación media/medianaDatos numéricos simplesSesgo posible
    LOCF o InterpolaciónSeries temporalesPuede suavizar en exceso
    Modelos predictivosDatos complejos o correlacionadosMayor esfuerzo computacional

    Manejar los datos faltantes no se trata solo de “rellenar huecos”, sino de preservar la integridad del análisis. Un buen tratamiento puede marcar la diferencia entre un modelo fiable y uno que toma decisiones erróneas. En análisis de datos, la ausencia también habla: cada valor faltante tiene una historia detrás, y entenderla es parte del trabajo de un buen analista.

  • Fundamentos de la Transformación de Datos

    Uno de los pasos fundamentales del Análisis Exploratorio de Datos (EDA) es el Data Wrangling. La transformación de datos es un conjunto de técnicas utilizadas para convertir datos de un formato o estructura a otro, con el fin de hacerlos más útiles, consistentes y listos para el análisis.

    En el proceso de preparación de datos, ciertas tareas suelen realizarse en un orden específico para maximizar la eficiencia y efectividad del flujo de trabajo. Un flujo de trabajo típico de limpieza y preparación de datos seria:

    1. Key restructuring (reestructuración de claves)
    2. Data validation (validación de datos)
    3. Data cleaning (limpieza de datos)
    4. Data deduplication (deduplicación de datos)
    5. Data derivation (derivación de datos)
    6. Format revisioning (revisión de formato)
    7. Data aggregation (agregación de datos)
    8. Data filtering (filtrado de datos)
    9. Data joining (unión de datos)
    10. Data integration (integración de datos)

    Este flujo de trabajo es iterativo y puede requerir ajustes según las necesidades específicas del proyecto y la naturaleza de los datos. Además, algunos pasos pueden superponerse o requerir revisiones cuando surgen nuevos datos o cambios en los requisitos del análisis.

    La razón principal para transformar los datos es obtener una representación más útil y compatible con otros conjuntos de datos. Además, la transformación adecuada favorece la interoperabilidad dentro de un sistema al seguir una estructura y formato común.

    Key Restructuring

    En el ámbito de la ciencia de datos, “Key Restructuring” se refiere a la reorganización o transformación de las claves en un conjunto de datos.
    Las “claves” suelen ser identificadores únicos o combinaciones de campos que sirven para relacionar registros entre sí.

    Renombrar Claves

    df.rename(columns={'old_name': 'new_name'}, inplace=True)

    Reasignar Valores de Clave

    df['key_column'] = df['key_column'].map(lambda x: 'new_value' if condition else x)

    Crear Claves Compuestas

    df['composite_key'] = df['key_part1'].astype(str) + '-' + df['key_part2'].astype(str)

    Eliminar Claves Innecesarias

    df.drop(columns=['unnecessary_key'], inplace=True)

    Asegurar la Unicidad

    if df['key_column'].is_unique:
        print("Las claves son únicas.")
    else:
        df.drop_duplicates(subset=['key_column'], inplace=True)

    Reindexación Basada en Claves

    df.set_index('key_column', inplace=True)

    Data Validation

    La validación de datos consiste en verificar si los datos cumplen con un conjunto de reglas o normas antes de ser procesados o analizados. Es una etapa crítica, ya que trabajar con datos erróneos o mal formateados puede llevar a conclusiones incorrectas y resultados poco confiables.

    Técnicas comunes en Pandas

    • Verificación de tipos de datos
    df.dtypes
    df['column'] = df['column'].astype(float)
    • Aplicar condiciones de validación
    assert (df['column'] > 0).all()
    • Validación de texto con expresiones regulares
    df['text_column'].str.match(r'^\w+$')
    • Detección de valores nulos
    df.isnull().sum()
    df.dropna(subset=['column'], inplace=True)
    • Valores únicos y duplicados
    df['column'].is_unique
    df.drop_duplicates(subset=['column'], inplace=True)
    • Rangos de valores
    df[(df['column'] >= min_value) & (df['column'] <= max_value)]
    • Validación de categorías
    allowed = {'cat1', 'cat2'}
    df['col'].isin(allowed)
    • Validación cruzada entre columnas
    df.apply(lambda row: row['col1'] < row['col2'], axis=1)

    La validación debe ser continua, adaptándose a las reglas del negocio y al tipo de análisis o modelo que se esté desarrollando.

    Data Cleaning

    La limpieza de datos busca detectar y corregir (o eliminar) registros corruptos, incompletos o inconsistentes, tratando valores faltantes y estandarizando formatos.

    Tareas comunes:

    • Detectar valores faltantes
    df.isnull()
    • Eliminar valores faltantes
    df.dropna()
    • Rellenar valores faltantes
    df.fillna(method='ffill')
    • Conversión de tipos
    df.astype({'col1': 'int32'})
    • Normalización de texto
    df['col'] = df['col'].str.strip().str.lower()
    • Manejo de outliers
      Filtrar o imputar valores extremos según percentiles o desviaciones estándar.
    • Manejo de fechas
    df['fecha'] = pd.to_datetime(df['fecha'], errors='coerce')
    • Guardar los datos limpios
    df.to_csv('clean_data.csv', index=False)

    Una limpieza adecuada es la base para cualquier análisis o modelado confiable.


    Data Deduplication

    La deduplicación de datos busca identificar y eliminar registros repetidos dentro de un conjunto de datos. Esto mejora la precisión y evita sesgos en el análisis.

    Métodos en Pandas:

    df.drop_duplicates()
    df.duplicated()

    Se puede usar el argumento subset para definir columnas específicas y keep para decidir qué duplicado conservar. Antes de eliminar duplicados, conviene analizar su origen y asegurarse de no eliminar información valiosa.

    Data Derivation

    La derivación de datos consiste en crear nuevas variables o columnas a partir de datos existentes.

    Ejemplos comunes:

    • Cálculo de estadísticas
    df['avg'] = df['value'].mean()
    • Transformaciones matemáticas
    df['normalized'] = (df['x'] - df['x'].mean()) / df['x'].std()
    • Descomposición de fechas
    df['year'] = df['date'].dt.year
    • One-hot encoding
    pd.get_dummies(df['category'])
    • Binning
    pd.cut(df['var'], bins=3)
    • Cálculo de diferencias
    df['diff'] = df['value'].diff()

    Derivar datos correctamente permite enriquecer el conjunto de análisis y mejorar el rendimiento de los modelos.

    Format Revisioning

    La revisión de formato implica convertir datos a tipos o estructuras adecuados para el análisis o interoperabilidad.

    • Conversión de tipos
    df['col'] = pd.to_numeric(df['col'], errors='coerce')
    • Normalización de texto
    df['texto'] = df['texto'].str.lower().str.strip()
    • Fechas y horas
    df['fecha'] = pd.to_datetime(df['fecha'])
    • Conversión a categorías
    df['cat'] = df['cat'].astype('category')
    • Exportar a otros formatos
    df.to_excel('datos.xlsx', index=False)
    df.to_sql('tabla', con=conexion)

    Data Aggregation

    La agregación de datos permite resumir información, extraer métricas y generar resúmenes útiles.

    Ejemplos:

    df.groupby('col')['ventas'].sum()
    df.groupby('col').agg({'ventas': ['mean', 'std']})
    df.pivot_table(values='ventas', index='mes', columns='region')
    pd.crosstab(df['categoria'], df['region'])
    df['ventas'].rolling(window=3).mean()
    df.resample('M')['ventas'].sum()

    La agregación facilita el análisis exploratorio y la generación de indicadores clave (KPIs).

    Data Filtering

    El filtrado de datos consiste en seleccionar subconjuntos relevantes según condiciones o criterios específicos.

    Ejemplos:

    df[df['edad'] > 30]
    df.query('columna > 100')
    df[df['pais'].isin(['España', 'Chile'])]
    df[(df['ventas'] > 500) & (df['region'] == 'Norte')]

    También puedes aplicar funciones personalizadas:

    df[df['nombre'].apply(lambda x: 'a' in x)]

    El filtrado ayuda a centrarse en los datos más relevantes y reduce ruido analítico.

    Top – Data Joining

    El data joining combina conjuntos de datos mediante claves comunes, similar a las uniones de SQL.

    Métodos:

    • pd.concat() – concatenar DataFrames (vertical u horizontalmente)
    • pd.merge() – unión tipo SQL (inner, left, right, outer)
    • df.join() – unión por índice o columna
    • merge_asof() y merge_ordered() – uniones temporales o ordenadas
    • compare() – detectar diferencias entre DataFrames

    Ejemplos:

    pd.concat([df1, df2], axis=0)
    pd.merge(df1, df2, on='id', how='left')

    La unión de datos es esencial para integrar fuentes diversas y construir un dataset analítico coherente.

  • Estructura de un Informe de Análisis de Datos

    Un informe de análisis de datos no es un artículo académico, ensayo ni informe de laboratorio. Es una conversación organizada con tu cliente o colaborador, con vida interna (memo extendido) y externa (para supervisores).

    Características Clave

    1. Fácil de ojear → Audiencias diferentes encuentran lo que necesitan rápido.
    2. Redacción invisible → El lector recuerda el contenido, no el estilo.

    Evita:

    • Prosa florída o demasiado casual.
    • Errores gramaticales.
    • Contexto inadecuado.
    • Enfocarse en proceso (salvo en apéndice).
    • Detalles técnicos innecesarios en el cuerpo.

    Estructura Básica

    SecciónContenido esencial
    IntroducciónResumen del estudio, datos, contexto, grandes preguntas, conclusiones clave y esquema del informe.
    CuerpoAnálisis principal con evidencia (tablas/gráficos).
    Conclusión/DiscusiónRepite preguntas + conclusiones. Añade observaciones y preguntas futuras.
    ApéndiceDetalles técnicos, tablas extras, código, salidas.

    Audiencias y Cómo Escribir para Cada Una

    AudienciaQué leeCómo facilitarles la vida
    Principal (cliente/colaborador)Introducción + Conclusión + ojea CuerpoOrganiza como una agenda de conversación: de general a específico o por importancia. Incluye evidencia clave en Cuerpo, detalles en Apéndice.
    EjecutivoSolo Introducción y ConclusiónDeja “titulares” claros en ambas secciones.
    Supervisor técnicoCuerpo + ApéndiceReferencias cruzadas específicas. Texto explicativo en Apéndice (cómo y por qué hiciste cada análisis).

    Organización del Cuerpo: 2 Formatos Efectivos

    1. Tradicional (familiar en psicología)

    • Datos
    • Métodos
    • Análisis
    • Resultados

    Riesgo:

    “Métodos” suena estéril sin resultados → fusiona con Análisis.

    2. Orientado a preguntas (recomendado)

    • Análisis
      • Tasa de Éxito
    • Métodos
    • Análisis
    • Conclusiones
      • Tiempo hasta Recaída
      • Efecto del Género

    Ventajas:

    • Sigue orden de la Introducción.
    • Cada subsección es autónoma.
    • Fácil de ojear.

    Reglas de Oro para el Cuerpo

    • 1–2 tablas/gráficos por pregunta → captan atención.
    • Evita exceso gráfico → rompe flujo → mueve extras al Apéndice.
    • Texto claro + evidencia visual = comprensión rápida.

    Apéndice: El Lugar de los Detalles

    Incluye:

    • Procedimientos estadísticos complejos.
    • Tablas/salidas detalladas.
    • Figuras secundarias.
    • Código comentado (¡con texto explicativo!).

    Regla:
    Cuerpo → lo justo para convencer.
    Apéndice → todo lo necesario para validar.


    Introducción: El Gancho Perfecto

    Debe incluir (en este orden):

    1. Resumen del estudio y datos.
    2. Contexto o problema.
    3. Grandes preguntas + conclusiones clave.
    4. Esquema del informe.

    Conclusión: Cierra con Impacto

    • Repite preguntas y respuestas.
    • Añade observaciones nuevas.
    • Propón preguntas futuras o próximos pasos.

    Checklist Final antes de Entregar

    • [ ] ¿Es fácil ojear para ejecutivos?
    • [ ] ¿Tiene agenda clara para el cliente?
    • [ ] ¿Apéndice valida todo para el supervisor?
    • [ ] ¿Redacción limpia y sin distracciones?
    • [ ] ¿1–2 visuales por pregunta?
    • [ ] ¿Referencias cruzadas entre Cuerpo y Apéndice?

    Conclusión:
    Un buen informe de datos no impresiona por su longitud.
    Impresiona porque tu cliente lo entiende, tu jefe lo aprueba y tu ejecutivo lo usa para decidir.

    Estructura simple. Audiencia clara. Contenido que habla.
    Eso es todo.