"""
ClaseB-238_Lunes_Sep_23.py
-----------------------------------
Hilario Iglesias Martínez
*************************************
Este es un programa en Python
se realiza una regresión lineal
utilizando el método de gradiente descendente
(Batch Gradient Descent)
El programa realiza una regresión lineal utilizando
el método de gradiente descendente
y visualiza los resultados a través de
gráficas. Es una implementación simple
pero efectiva de un modelo de regresión lineal.
***********************************************
Programa realizado bajo una plataforma Linux:
Ubuntu 20.04.6 LTS.
Editado con: Sublime Text.
*********************************
Ejecución bajo consola Linux.
python3 ParaClaseLunes-Sep-F543.PY
*******************************************
"""
#Importación de biblioteca:NumPy realiza operaciones matriciales.
#Importación de Matplotlib para la creación de gráficos.
import numpy as np
import matplotlib.pyplot as plt
# Datos aleatorios de ejemplo.
"""
Se generan datos de ejemplo Aleatorios_X, y
Aleatorios_y. Utilizando la función np.random.rand de NumPy.
Estos datos se utilizan para entrenar el modelo de regresión.
"""
np.random.seed(0)
Aleatorios_X = 2 * np.random.rand(150, 1)
Aleatorios_y = 4 + 3 * Aleatorios_X + np.random.randn(150, 1)
# Inicialización de parámetros (pendiente y ordenada al origen)
Pendiente = 0
Intercepto = 0
#Parámetros de Tasa de aprendizaje, y Iteraciones o epoch.
Tasa_Aprendizaje=0.01
Iteraciones = 100
# Listas para guardar los valores de pérdida y parámetros en cada iteración.
"""
Perdidas, Pendientes, e Interceptos
son listas vacías que se utilizarán
para almacenar los valores de pérdida,
y los parámetros en cada iteración.
"""
Perdidas = []
Pendientes = []
Interceptos = []
# Bucle de iteración
"""
Se ejecuta un bucle for que itera a través del
número de iteraciones especificado.
En cada iteración, se calculan las predicciones (Predicciones)
utilizando la ecuación de regresión lineal.
Se calcula el error entre las predicciones y los valores reales.
Se calculan los gradientes (Gradiente_Pendiente y Gradiente_Intercepto)
utilizando el gradiente descendente para actualizar los parámetros
(Pendiente e Intercepto).
Se calcula la función de pérdida, que es el error cuadrático medio.
Los valores de pérdida, pendiente e intercepto se almacenan en
las listas correspondientes para su posterior visualización.
"""
for vueltas in range(Iteraciones):
# Cálculo de las predicciones
Predicciones = Pendiente * Aleatorios_X + Intercepto
# Cálculo del error
Error = Aleatorios_y - Predicciones
# Cálculo de los gradientes
Gradiente_Pendiente = (-2 / len(Aleatorios_X)) * np.sum(Aleatorios_X * Error)
Gradiente_Intercepto = (-2 / len(Aleatorios_X)) * np.sum(Error)
# Actualización de parámetros
Pendiente -= Tasa_Aprendizaje * Gradiente_Pendiente
Intercepto -= Tasa_Aprendizaje * Gradiente_Intercepto
# Cálculo de la función de pérdida (Error cuadrático medio)
Perdida = np.mean(Error ** 2)
# Almacenar valores para graficar
Perdidas.append(Perdida)
Pendientes.append(Pendiente)
Interceptos.append(Intercepto)
# Parámetros finales
Final_Pendiente = Pendientes[-1] if Pendientes else 0
Final_Intercepto = Interceptos[-1] if Interceptos else 0
#******************************************************
"""
Se realizan tres predicciones (nuevo_x, nuevo1_x, y nuevo2_x)
utilizando la pendiente e intercepto finales obtenidos después
de todas las iteraciones.
"""
m = Pendiente
b = Intercepto
nuevo_x = np.array([[0.5]]) # Nuevo valor de x
nuevo_y = m * nuevo_x + b
nuevo1_x = np.array([[0.8]]) # Nuevo valor de x
nuevo1_y = m * nuevo1_x + b
nuevo2_x = np.array([[0.6]]) # Nuevo valor de x
nuevo2_y = m * nuevo2_x + b
#*****************************************************
# Gráfica de la pérdida en función de las Iteraciones.
"""
Se crea una figura con dos subgráficos:
El primer subgráfico muestra la pérdida
en función de las iteraciones.
El segundo subgráfico muestra los datos reales,
la línea de regresión ajustada y las predicciones realizadas.
"""
plt.figure(figsize=(14, 6))
plt.subplot(1, 2, 1)
plt.plot(range(1, Iteraciones + 1), Perdidas, marker='o')
plt.xlabel('Iteraciones')
plt.ylabel('Pérdida')
plt.title('Pérdida en función de las Iteraciones')
# Gráfica de la regresión lineal ajustada
plt.subplot(1, 2, 2)
plt.scatter(Aleatorios_X, Aleatorios_y, label='Datos reales')
plt.plot(Aleatorios_X, Final_Pendiente * Aleatorios_X + Final_Intercepto, color='red',
label='Regresión lineal,m: 3.4501,b: 3.2805')
plt.scatter(nuevo_x, nuevo_y, color='black', marker='o', s=100, label='Prueba de predicción_0')
plt.scatter(nuevo1_x, nuevo1_y, color='black', marker='o', s=100, label='Prueba de predicción_1')
plt.scatter(nuevo2_x, nuevo2_y, color='black', marker='o', s=100, label='Prueba de predicción_2')
plt.xlabel('Eje X')
plt.ylabel('Eje y')
plt.legend()
plt.title('Regresión Lineal')
plt.tight_layout()
plt.show()
#Impresión de parámetros finales:
print("*************************************************")
print(f"Pendiente final, m: {Final_Pendiente:.4f}")
print(f"Ordenada al origen final, b: {Final_Intercepto:.4f}")
print("*************************************************")
"""
*************************************************
Pendiente final, m: 3.4501
Ordenada al origen final, b: 3.2805
*************************************************
"""