######################################################################################
#                    Régression multiple et polynomiale                              #
######################################################################################
import random as rd
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from sklearn.linear_model import LinearRegression


## Importation des données

chemin ="Donnees_mystere.csv"   # Importation des données du fichier ".csv" dans la DataFrame : "dataset"
dataset = pd.read_csv(chemin)
        # Création de la matrice des entrées "X" et du vecteur des sorties "Y"
Entrees = dataset[["Entrées1 = Xa", "Entrées2 = Xb"]].to_numpy(dtype=float)
Sorties = dataset[["Sorties = Y"]].to_numpy(dtype=float)

## Affichage des données dans un graphique 3D et Création de la matrice de la régression

def Trace_donnees(X,Y,Montrer):
    ax=plt.axes(projection='3d')
    ax.scatter(X[:,0],X[:,1],Y[:,0])
    ax.set_xlabel('Entrées1 = Xa')
    ax.set_ylabel('Entrées2 = Xb')
    ax.set_zlabel('Sorties = Y')
    if Montrer==True:
        plt.show()

def Mat_donnees(entrees_brutes:np.array,L_degres:list)->np.array:
    Ndonnees,Nparam=np.shape(entrees_brutes)
    donnees=np.ones((Ndonnees,sum(L_degres)))
    colonne=0
    for ip in range(Nparam):
        degre=1
        for id in range(L_degres[ip]):
            donnees[:,colonne]=(entrees_brutes[:,ip])**degre
            degre+=1
            colonne+=1
    return donnees



## Algorithme de la régression


def Regression(Entrees,Sorties,L_degre):
        # Construction de la matrice de données
    Xd=Mat_donnees(Entrees,L_degre)
    Model=LinearRegression()
    Model.fit(Xd,Sorties)
    graphique(Entrees,Sorties,Model,L_degre)
    print('coefficient constant :', Model.intercept_)
    print('Coefficients polynomiaux :',Model.coef_)
    #print('Erreur moyenne (sqrt(r2)) :',r2_score(Sorties, Model.predict(Xd)))
    return Model

## Affichage des résultats et des données dans un graphique 3D

def graphique(X,Y,Model,L_degre):
    Trace_donnees(X,Y,False)
    ax=plt.axes(projection='3d')
    ax.scatter(X[:,0],X[:,1],Y[:,0])
    ax.set_xlabel('Entrées1 = Xa')
    ax.set_ylabel('Entrées2 = Xb')
    ax.set_zlabel('Sorties = Y')
    GX = np.linspace(10,40,16)      # Tableau des abscisses (16)
    GY = np.linspace(10,40,16)      # Tableau des ordonnées (16)
    Z=np.zeros((len(GX),len(GY)))   # tableau des altitudes (16 x 16)
                # Détermination des altitudes à partir des prédictions du modèle
    for k in range(len(GY)):
        for l in range (len(GX)):
            vecteur_donnee=[]
            for j in range(L_degre[0]):
                vecteur_donnee.append(GX[l]**(j+1))
            for j in range(L_degre[1]):
                vecteur_donnee.append(GY[k]**(j+1))
            #print(vecteur)
            Z[k,l]=Model.predict([vecteur_donnee])
                # tracé de la surface de prédiction
    GX, GY = np.meshgrid(GX, GY)    # Grilles 16 x 16
    ax.plot_surface(GX, GY, Z, cmap='plasma', alpha=0.5)
    plt.show()



