Módulo: regression_analysis.py#

Este es el módulo que se encarga de hacer el análisis de los datos, para ello utiliza diferentes métodos como lo son: regresión lineal, regresión polinómica e interpolación.

class src.regression_analysis.DataOps#

Bases: object

Clase auxiliar que contiene el atributo “data”.

__init__(data)#
def __init__(self, data):
    self.data = data
class src.regression_analysis.RegressionAnalysis#

Bases: object

Clase para realizar diferentes tipos de análisis de regresión e interpolación.

Esta clase proporciona métodos para regresión lineal, regresión polinómica e interpolación de Lagrange, junto con visualización de resultados y cálculo de métricas.

Parámetros:

data_ops – Objeto de operaciones de datos que contiene el conjunto de datos a analizar

Atributos:

data_ops: Objeto de operaciones de datos que contiene el conjunto de datos

__init__(data_ops)#

Inicializa la clase con operaciones de datos.

Si el argumento es un DataFrame, crea un objeto data_ops y asigna el DataFrame a su atributo data. Si no, no hace nada.

Parámetros:

data_ops – Un objeto que puede ser un DataFrame o una clase con atributo data.

def __init__(self, data_ops):

    if isinstance(data_ops, pd.DataFrame):
        # Si el argumento es un DataFrame, crea un objeto 'data_ops' con el DataFrame
        self.data_ops = DataOps(data_ops)  # Crea el objeto 'data_ops' y asigna el DataFrame a su atributo 'data'
    elif hasattr(data_ops, 'data'):
        # Si el argumento ya es un objeto con el atributo 'data', simplemente lo asigna
        self.data_ops = data_ops
    else:
        self.data_ops = None  # No hace nada si no es un DataFrame ni un objeto con el atributo 'data'
calculate_metrics(y_true, y_pred)#

Calcula métricas de regresión entre valores reales y predichos.

Parámetros:
  • y_true (array-like) – Valores reales

  • y_pred (array-like) – Valores predichos

Devuelve:

Métricas R-cuadrado, Error Absoluto Medio y Error Cuadrático Medio

Tipo del valor devuelto:

tuple

def calculate_metrics(self, y_true, y_pred):

    r2 = r2_score(y_true, y_pred)
    mae = mean_absolute_error(y_true, y_pred)
    mse = mean_squared_error(y_true, y_pred)
    return r2, mae, mse
format_equation(coefficients)#

Formatea los coeficientes de regresión en una ecuación legible.

Parámetros:

coefficients (array-like) – Coeficientes de regresión

Devuelve:

Cadena de texto con la ecuación formateada

Tipo del valor devuelto:

str

def format_equation(self, coefficients):

    if len(coefficients) == 2:  # Regresión lineal
        return f'y = {coefficients[0]:.4f}x + {coefficients[1]:.4f}'
    else:  # Regresión polinómica
        eq = 'y = '
        for i, coef in enumerate(coefficients):
            power = len(coefficients) - i - 1
            if power > 1:
                eq += f'{coef:.4f}x^{power} + '
            elif power == 1:
                eq += f'{coef:.4f}x + '
            else:
                eq += f'{coef:.4f}'
        return eq
linear_regression(var_x, var_y, ax1=None, return_metrics=False)#

Realiza análisis de regresión lineal y visualización.

Parámetros:
  • var_x (str) – Nombre de la columna de variable independiente

  • var_y (str) – Nombre de la columna de variable dependiente

  • ax1 (matplotlib.axes.Axes, optional) – Eje de la gráfica donde se va a dibujar la regresión

  • return_metrics (bool, optional) – Si es True, devuelve solo la ecuación y métricas, si es False, dibuja la regresión sobre el gráfico.

Advertencias:

Muestra diálogo de advertencia si no se seleccionan variables o no hay datos cargados.

def linear_regression(self, var_x, var_y, ax1=None, return_metrics=False):

    if self.data_ops.data is not None and var_x in self.data_ops.data.columns and var_y in self.data_ops.data.columns:
        x = self.data_ops.data[var_x].values.reshape(-1, 1)
        y = self.data_ops.data[var_y].values
        model = LinearRegression()
        model.fit(x, y)
        y_pred = model.predict(x)

        # Si se indica que no se devuelvan solo métricas, graficar la regresión
        if not return_metrics:
            if ax1 is not None:
                # Graficar los puntos y la línea de regresión en el gráfico existente
                ax1.plot(x, y_pred, color='red', label='Regresión', linewidth=2)
                ax1.legend()

        # Calcular métricas y formatear la ecuación
        r2, mae, mse = self.calculate_metrics(y, y_pred)
        metrics_text = f'R² = {r2:.4f}\nMAE = {mae:.4f}\nMSE = {mse:.4f}'
        equation = self.format_equation([model.coef_[0], model.intercept_])

        # Si se indican métricas, devolver la ecuación y las métricas
        if return_metrics:
            # Crear figura con dos subplots
            fig, (ax1, ax2) = plt.subplots(2, 1, height_ratios=[3, 1], figsize=(10, 8))
            fig.suptitle('Análisis de Regresión Lineal', fontsize=14)

            # Graficar regresión
            ax1.scatter(x, y, color='blue', label='Datos')
            ax1.plot(x, y_pred, color='red', label='Regresión')
            ax1.set_xlabel(var_x)
            ax1.set_ylabel(var_y)
            ax1.legend()

            # Mostrar métricas y ecuación
            ax2.text(0.5, 0.5, f'{equation}\n\n{metrics_text}',
                    horizontalalignment='center',
                    verticalalignment='center',
                    transform=ax2.transAxes,
                    bbox=dict(facecolor='white', alpha=0.8))
            ax2.axis('off')

            plt.tight_layout()
            return fig
        else:
            # Devolver los datos de la regresión para ser graficados
            return x, y_pred, equation

    else:
        messagebox.showwarning("Advertencia", "Selecciona las variables primero")
polynomial_regression(var_x, var_y, ax1=None, return_metrics=False)#

Realiza análisis de regresión polinómica y visualización.

Parámetros:
  • var_x (str) – Nombre de la columna de variable independiente

  • var_y (str) – Nombre de la columna de variable dependiente

  • ax1 (matplotlib.axes.Axes, optional) – Eje de la gráfica donde se va a dibujar la regresión

  • return_metrics (bool, optional) – Si es True, devuelve solo la ecuación y métricas, si es False, dibuja la regresión sobre el gráfico.

Advertencias:
  • Muestra diálogo de advertencia si no se seleccionan variables o no hay datos cargados

  • Diálogo para ingresar el grado del polinomio (1-10)

Salida:
  • Gráfico de dispersión con curva de regresión polinómica

  • Cuadro de texto con ecuación polinómica y métricas

def polynomial_regression(self, var_x, var_y, ax1=None, return_metrics=False):

    if self.data_ops.data is not None and var_x and var_y:
        degree = simpledialog.askinteger("Grado del Polinomio", 
                                    "Ingresa el grado del polinomio:", 
                                    minvalue=1, maxvalue=10)

        if degree is not None:
            x = self.data_ops.data[var_x]
            y = self.data_ops.data[var_y]
            coef = np.polyfit(x, y, degree)
            poly_eq = np.poly1d(coef)

            # Solo generar los puntos ajustados para el rango de datos original
            y_fit = poly_eq(x)

            # Si se indica que no se devuelvan solo métricas, graficar la regresión
            if not return_metrics:
                if ax1 is not None:
                    # Graficar los puntos y la línea de regresión en el gráfico existente
                    ax1.scatter(x, y, color='blue', label='Datos')
                    ax1.plot(x, y_fit, color='red', label=f'Regresión Polinómica (Grado {degree})')
                    ax1.legend()

            # Calcular y devolver las métricas si se solicitan
            r2, mae, mse = self.calculate_metrics(y, y_fit)
            equation = self.format_equation(coef)

            if return_metrics:
                x_fit = np.linspace(x.min(), x.max(), 100)
                y_fit = poly_eq(x_fit)

                # Crear figura con dos subplots
                fig, (ax1, ax2) = plt.subplots(2, 1, height_ratios=[3, 1], figsize=(10, 8))
                fig.suptitle(f'Análisis de Regresión Polinómica (Grado {degree})', fontsize=14)

                # Graficar regresión
                ax1.scatter(x, y, color='blue', label='Datos')
                ax1.plot(x_fit, y_fit, color='red', 
                        label=f'Regresión Polinómica')
                ax1.set_xlabel(var_x)
                ax1.set_ylabel(var_y)
                ax1.legend()

                # Calcular y mostrar métricas
                r2, mae, mse = self.calculate_metrics(y, poly_eq(x))
                metrics_text = f'R² = {r2:.4f}\nMAE = {mae:.4f}\nMSE = {mse:.4f}'
                equation = self.format_equation(coef)

                # Mostrar métricas y ecuación
                ax2.text(0.5, 0.5, f'{equation}\n\n{metrics_text}',
                        horizontalalignment='center',
                        verticalalignment='center',
                        transform=ax2.transAxes,
                        bbox=dict(facecolor='white', alpha=0.8))
                ax2.axis('off')

                plt.tight_layout()
                return fig
            else:
                return x, y_fit, equation

    else:
        messagebox.showwarning("Advertencia", "Selecciona las variables para la regresión")
interpolation(var_x, var_y, ax1=None, return_metrics=False)#

Realiza interpolación de Lagrange y visualización.

Parámetros:
  • var_x (str) – Nombre de la columna de variable independiente

  • var_y (str) – Nombre de la columna de variable dependiente

  • ax1 (matplotlib.axes.Axes, optional) – Eje de la gráfica donde se va a dibujar la interpolación

  • return_metrics (bool, optional) – Si es True, devuelve solo el polinomio de interpolación y métricas, si es False, dibuja la interpolación sobre el gráfico.

Advertencias:

Muestra diálogo de advertencia si no se seleccionan variables o no hay datos cargados. Diálogo para ingresar el grado de interpolación (1-10). Advertencia si no hay suficientes puntos para el grado seleccionado.

Salida:
  • Gráfico de dispersión con curva de interpolación (si return_metrics es False)

  • Cuadro de texto con polinomio de Lagrange y métricas

def interpolation(self, var_x, var_y, ax1=None, return_metrics=False):

    if self.data_ops.data is not None and var_x and var_y:
        degree = simpledialog.askinteger("Grado del Polinomio", 
                                        "Ingresa el grado del polinomio:", 
                                        minvalue=1, maxvalue=10)

        if degree is not None:
            x = self.data_ops.data[var_x].values
            y = self.data_ops.data[var_y].values

            if len(x) < degree + 1:
                messagebox.showwarning("Advertencia", 
                                    "No hay suficientes puntos para el grado seleccionado")
                return

            # Selección de puntos: primer, intermedio(s) y último
            indices = np.linspace(0, len(x) - 1, degree + 1, dtype=int)
            x_points = x[indices]
            y_points = y[indices]

            # Generación de la función de interpolación de Lagrange
            def lagrange_interpolation_expression(x_points, y_points):
                n = len(x_points)
                terms = []
                for i in range(n):
                    numerator = []
                    denominator = 1
                    for j in range(n):
                        if i != j:
                            numerator.append(f"(x - {x_points[j]:.4f})")
                            denominator *= (x_points[i] - x_points[j])
                    term = f"({y_points[i]:.4f} / {denominator:.4f}) * " + " * ".join(numerator)
                    terms.append(term)
                return "P(x) = " + " + ".join(terms)

            def lagrange_interpolation(x_eval, x_points, y_points):
                n = len(x_points)
                result = 0
                for i in range(n):
                    term = y_points[i]
                    for j in range(n):
                        if i != j:
                            term *= (x_eval - x_points[j]) / (x_points[i] - x_points[j])
                    result += term
                return result

            # Generar los datos interpolados
            y_interpolated = np.array([lagrange_interpolation(x_val, x_points, y_points) for x_val in x])

            # Generar expresión algebraica
            expression = lagrange_interpolation_expression(x_points, y_points)

            # Si no se requieren solo métricas, graficar la interpolación
            if not return_metrics:
                if ax1 is not None:
                    ax1.scatter(x, y, color='blue', label='Datos originales')
                    ax1.plot(x, y_interpolated, color='red', label='Interpolación')
                    ax1.set_xlabel(var_x)
                    ax1.set_ylabel(var_y)
                    ax1.legend()

            # Calcular métricas
            r2, mae, mse = self.calculate_metrics(y, y_interpolated)
            metrics_text = f'R² = {r2:.4f}\nMAE = {mae:.4f}\nMSE = {mse:.4f}'

            # Si se indican métricas, devolver la ecuación y las métricas
            if return_metrics:
                # Crear figura con dos subplots
                fig, (ax1, ax2) = plt.subplots(2, 1, height_ratios=[3, 1], figsize=(10, 8))
                fig.suptitle(f'Interpolación de Lagrange (Grado {degree})', fontsize=14)

                # Graficar interpolación
                ax1.scatter(x, y, color='blue', label='Datos originales')
                ax1.plot(x, y_interpolated, color='red', label='Interpolación')
                ax1.set_xlabel(var_x)
                ax1.set_ylabel(var_y)
                ax1.legend()

                # Mostrar métricas y ecuación
                ax2.text(0.5, 0.5, f'{expression}\n\n{metrics_text}',
                        horizontalalignment='center',
                        verticalalignment='center',
                        transform=ax2.transAxes,
                        bbox=dict(facecolor='white', alpha=0.8), fontsize=8, wrap=True)
                ax2.axis('off')

                plt.tight_layout()
                return fig
            else:
                return x, y_interpolated, expression

    else:
        messagebox.showwarning("Advertencia", "Selecciona las variables primero")