3) Meteo et machine learning

Pour cette suite, on va cette fois cuisiner un dataset regroupant 29 stations (on gardera les stations qui ont le moins de données manquantes sur les trois ans), avec toujours les mêmes variables relevées toutes les 2 heures. Comme il y a 29 stations il va falloir les différentier dans nos données, c’est pourquoi on ajoutera trois nouvelles variables: latitude, longitude et altitude. Dans un premier temps on va se focaliser là-dessus. Au besoin, on remodifiera tout ça. La taille du dataset d’origine va donc cette fois faire 31784 échantillons pour 63 variables. Pour rappel, l’objectif initial est de prévoir le plus précisément possible la force et la direction du vent en Manche 12 heures après la récolte d’infos prises sur 24 heures.

Préparer les données

Pour le projet de station meteo j’ai déniché une girouette/anémo électronique pas trop chère, cependant la girouette ne relève pas un cap précis mais plutôt une fourchette de cap; elle n’indique que les 8 caps de base (N,NE,E,SE,S,SO,O,NO). Donc il va également falloir modifier le dataset pour ça, ainsi que modifier les modèles prédictifs utilisées pour la direction du vent. En effet on passe d’un problème de régression à un problème de classification maintenant (classification multiclasse car on a donc 8 classes, une pour chaque cap). Tout bien réfléchit, pour la force du vent on va aussi changer les données mais seulement pour les données test (l’anémo va nous fournir une donnée continue, pas discrète) afin de passer d’un problème de régression à un problème de classification (pour simplifier et améliorer la prédiction de nos modèles). Voilà le programme pour obtenir notre dataset à partir des données météo france:

On fait ce code pour chaque année pour la première partie, puis on passe les trois fichiers csv obtenus à la moulinette de la seconde partie de code:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime



def cap(var):
    
    if (var>337.5) and (var<=22.5):
        var=0
    elif (var>22.5) and (var<=67.5):
        var=45
    elif (var>67.5) and (var<=112.5):
        var=90
    elif (var>112.5) and (var<=157.5):
        var=135
    elif (var>157.5) and (var<=202.5):
        var=180
    elif (var>202.5) and (var<=247.5):
        var=225
    elif (var>247.5) and (var<=292.5):
        var=270
    else:
        var=315
        
    return var



def videur(data):
    
    data=data.sort_values(['number_sta','date'],ascending=True)
    data=data.drop(['precip','td'],axis=1)
    data=data.set_index('date')
    data=data.fillna(data.rolling(window=1).mean())
    data=data.dropna(axis=0)
    data.index=pd.to_datetime(data.index)
    
    heure_1=data[(data.index.minute==0) & (data.index.second==0)] #on conserve juste les données toutes les heures pour chaque station.
    liste=[heure_1]
    data=pd.concat(liste,axis=0)
    data=data.sort_values(['number_sta','date'],ascending=True)
    
    data['t']=data['t'].map(lambda x:int(x-273.15)) #convertit les Kelvin en degrés celsius.
    data['psl']=data['psl'].map(lambda x:int(x/100)) #convertit les pascals en hectopascals.
    data['hu']=data['hu'].map(lambda x:int(x)) #change en entier
    data['dd']=data['dd'].map(lambda x:int(x)) #pareil
    data['height_sta']=data['height_sta'].map(lambda x:int(x)) #encore pareil
    data['ff']=data['ff'].map(lambda x:int(x*3600/1852)) #change la vitesse du vent en noeuds.
    data['dd']=data['dd'].map(lambda var:cap(var)) # on modifie la direction du vent pour notre future girouette.
    data['number_sta']=data['number_sta'].map(lambda x:int(x)) # change les float en int pour economiser de la memoire.
    
    return data
    

    
    

chunksize=100000
chunks=[]

for chunk in pd.read_csv('C:/Users/Psychopathe/Documents/cours tech/machine learning/meteonet-master/NW_Ground_Stations/Meteo_NW_2018.csv',chunksize=chunksize):
    vide=videur(chunk)
    chunks.append(vide)
    
data_an_2018=pd.concat(chunks,axis=0)
    
data_an_2018.to_csv('2018_one.csv',sep='\t')
    
import numpy as np
import pandas as pd
from datetime import datetime

'''on importe les données précédemment filtrées'''

data_16=pd.read_csv('C:/Users/Psychopathe/Documents/Python Scripts/meteo/station maison/programmes/traitement 40 stations/2016_one.csv',sep='\t')
data_17=pd.read_csv('C:/Users/Psychopathe/Documents/Python Scripts/meteo/station maison/programmes/traitement 40 stations/2017_one.csv',sep='\t')
data_18=pd.read_csv('C:/Users/Psychopathe/Documents/Python Scripts/meteo/station maison/programmes/traitement 40 stations/2018_one.csv',sep='\t')

'''on compte le nombre de lignes de données par station par an'''

selection_16=data_16['number_sta'].value_counts()
selection_17=data_17['number_sta'].value_counts()
selection_18=data_18['number_sta'].value_counts()

'''on sélectionne les 40 stations qui ont le plus de données par année'''

select_16=selection_16[:40]
select_17=selection_17[:40]
select_18=selection_18[:40]

'''on met le tout dans une grande série puis on garde les stations qui apparaissent dans les trois années après ce second tri'''

liste=[select_16,select_17,select_18]

select=pd.concat(liste,axis=0)

print(select.index.nunique())
print(select.index.value_counts())

select_stations=select.index.value_counts()
select_final=select_stations[:29] # il reste au final 29 stations.

palme=[] #on met les numéros des stations dans une liste.
for val in select_final.index: # on met les index, les num des stations en liste.
    palme.append(val)
  
    
data_toto=[data_16,data_17,data_18]
data_toto=pd.concat(data_toto,axis=0)

stations=[] #cette liste va prendre les stations traitées par la boucle for.
for station in palme:
    sta=data_toto.loc[data_toto['number_sta']==station]
    sta=sta.set_index('date')
    sta.index=pd.to_datetime(sta.index)
    sta=sta.resample('2H').ffill()
    sta=sta.drop(['number_sta'],axis=1)
    heures_sta=[sta[sta.index.hour==2*i] for i in range(12)]
    done=np.concatenate(heures_sta,axis=1)
    stations.append(done)
    
données=np.concatenate(stations,axis=0)
données_totales=pd.DataFrame(données)

lat=[8+8*i for i in range(11)] #permet d'eliminer les colonnes latitude en trop.
lon=[9+8*i for i in range(11)] #permet d'eliminer les colonnes longitude en trop.
alt=[10+8*i for i in range(10)] #permet d'enlever les colonnes altitude en trop.

print(données_totales.iloc[1095,:])
print(données_totales.iloc[1096,:])
print(données_totales.iloc[1097,:])


données_totales=données_totales.drop(lat+lon+alt,axis=1) #on vire les colonnes inutiles.

last=[1096+1096*i for i in range(28)]
données_totales_var=données_totales.drop(last,axis=0) #on vire la dernière ligne de données pour chaque station.

first=[1095*i for i in range(28)]
données_totales_dir=données_totales.iloc[:,33].drop(first,axis=0) #pareil mais cette fois la première lignepour chaque station.
données_totales_for=données_totales.iloc[:,34].drop(first,axis=0)
données_totales_hu=données_totales.iloc[:,35].drop(first,axis=0)
données_totales_tem=données_totales.iloc[:,36].drop(first,axis=0)
données_totales_pr=données_totales.iloc[:,37].drop(first,axis=0)


données_totales_var.to_csv('données_totales_var.csv',sep='\t')
données_totales_dir.to_csv('données_totales_dir.csv',sep='\t')
données_totales_for.to_csv('données_totales_for.csv',sep='\t')
données_totales_hu.to_csv('données_totales_hu.csv',sep='\t')
données_totales_tem.to_csv('données_totales_tem.csv',sep='\t')
données_totales_pr.to_csv('données_totales_pr.csv',sep='\t')

Les modèles et leurs résultats

Bon ça c’est fait. Pour tout les modèles que l’on va solliciter on va à chaque fois chercher les meilleurs paramètres via GridSearchCV, utiliser des pipelines quand c’est nécessaire (besoin de prétraitement des données), vérifier les variables les plus utilisées, et tracer une courbe d’apprentissage pour voir si le modèle est encore en capacité de s’améliorer si on lui injecte de nouvelles données.

  1. arbre de décision et forêt aléatoire

Maintenant, pour commencer et faire simple on va soumettre notre dataset à un modèle basique d’arbre de décision (DecisionTreeClassifier) qui ne nécessite pas de prétraitement. Ensuite on va faire ce qu’on appelle du ‘bagging’, on va fabriquer plein d’arbres de décision légèrement différents les uns des autres, puis faire le résumé de leur prédictions pour avoir une prédiction globale, bref on va utiliser une forêt aléatoire (RandomForestClassifier). Voilà ce que ça donne avec l’arbre de décision:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from fonction_force import force # cette fonction permet de classer les forces de vent en catégories.


from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import learning_curve

from sklearn.tree import DecisionTreeClassifier

variables=pd.read_csv('C:/Users/Psychopathe/Documents/Python Scripts/meteo/station maison/mercredi11novembre/variables29.csv',sep='\t',index_col=0)
dir_test=pd.read_csv('C:/Users/Psychopathe/Documents/Python Scripts/meteo/station maison/mercredi11novembre/dir_test_29.csv',sep='\t',index_col=0)
for_test=pd.read_csv('C:/Users/Psychopathe/Documents/Python Scripts/meteo/station maison/mercredi11novembre/for_test_29.csv',sep='\t',index_col=0)

for_test.iloc[:,0]=for_test.iloc[:,0].map(lambda x:force(x))


dir_test=np.ravel(dir_test)
for_test=np.ravel(for_test)


X_train_dir,X_test_dir,y_train_dir,y_test_dir=train_test_split(variables,dir_test,test_size=0.3)
X_train_for,X_test_for,y_train_for,y_test_for=train_test_split(variables,for_test,test_size=0.3)

''' recherche du meilleur arbre de décision pour la direction du vent'''

params_dir={
     'max_depth':[4,5,6,7,8],
     
        }

grille_dir=GridSearchCV(DecisionTreeClassifier(),params_dir,cv=5)
grille_dir.fit(X_train_dir,y_train_dir)
model_dir=grille_dir.best_estimator_
print(grille_dir.best_params_)
print(model_dir.score(X_train_dir,y_train_dir))
print(model_dir.score(X_test_dir,y_test_dir))

''' recherche du meilleur arbre de décision pour la force du vent'''

params_for={
    'max_depth':[4,5,6,7,8],
    }

grille_for=GridSearchCV(DecisionTreeClassifier(),params_for,cv=5)
grille_for.fit(X_train_for,y_train_for)
model_for=grille_for.best_estimator_
print(grille_for.best_params_)
print(model_for.score(X_train_for,y_train_for))
print(model_for.score(X_test_for,y_test_for))

print(model_dir.feature_importances_) #indique les variables les plus utilisées par le modèle.
print(model_for.feature_importances_)

N,train_score,val_score=learning_curve(model_for,X_train_for,y_train_for,train_sizes=np.linspace(0.2,1,5),cv=5)
plt.plot(N,train_score.mean(axis=1),label='train')
plt.plot(N,val_score.mean(axis=1),label='validation')
plt.xlabel('train_sizes')
plt.legend()
plt.title('force du vent')

Rapidement voici le prog pour la fonction force vu précédemment:

import numpy as np
import pandas as pd

def force(var):
    
        if (var>=0) and (var<5):
            var=1
        elif (var>=5) and (var<10):
            var=2
        elif (var>=10) and (var<15):
            var=3
        elif (var>=15) and (var<20):
            var=4
        elif (var>=20) and (var<25):
            var=5
        elif (var>=25) and (var<30):
            var=6
        elif (var>=30) and (var<35):
            var=7
        else:
            var=8
        return var

et maintenant les 2 courbes d’apprentissage:

A première vue c’est pas mal, les courbes de test augmentent au fur et à mesure bien que celle de la direction du vent aie une pente plus faible. Donc l’ajout d’échantillons supplémentaires dans ce modèle devrait améliorer les scores (surtout pour la force du vent), , vu qu’on ne distingue pas de palier tranché sur ces courbes. Croisons les twix comme on dit !

Maintenant avec les forêt aléatoire:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from fonction_force import force # cette fonction permet de classer les forces de vent en catégories.


from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import learning_curve

from sklearn.ensemble import RandomForestClassifier

variables=pd.read_csv('C:/Users/Psychopathe/Documents/Python Scripts/meteo/station maison/mercredi11novembre/variables29.csv',sep='\t',index_col=0)
dir_test=pd.read_csv('C:/Users/Psychopathe/Documents/Python Scripts/meteo/station maison/mercredi11novembre/dir_test_29.csv',sep='\t',index_col=0)
for_test=pd.read_csv('C:/Users/Psychopathe/Documents/Python Scripts/meteo/station maison/mercredi11novembre/for_test_29.csv',sep='\t',index_col=0)

for_test.iloc[:,0]=for_test.iloc[:,0].map(lambda x:force(x))


dir_test=np.ravel(dir_test)
for_test=np.ravel(for_test)


X_train_dir,X_test_dir,y_train_dir,y_test_dir=train_test_split(variables,dir_test,test_size=0.3)
X_train_for,X_test_for,y_train_for,y_test_for=train_test_split(variables,for_test,test_size=0.3)

''' recherche du meilleur potager pour la direction du vent '''

params_dir={
    'max_features':[8],
    'n_estimators':[250],
    'max_depth':[15,10],
    'n_jobs':[2]
    }

grille_dir=GridSearchCV(RandomForestClassifier(),params_dir,cv=5)
grille_dir.fit(X_train_dir,y_train_dir)
model_dir=grille_dir.best_estimator_
print(grille_dir.best_params_)
print(model_dir.score(X_train_dir,y_train_dir))
print(model_dir.score(X_test_dir,y_test_dir))

''' recherche du meilleur potager pour la force du vent '''
params_for={
    
    'max_features':[8],
    'n_estimators':[250],
    'max_depth':[15,10],
    'n_jobs':[2]
    }




grille_for=GridSearchCV(RandomForestClassifier(),params_for,cv=5)
grille_for.fit(X_train_for,y_train_for)
model_for=grille_for.best_estimator_
print(grille_for.best_params_)
print(model_for.score(X_train_for,y_train_for))
print(model_for.score(X_test_for,y_test_for))

print(model_for.feature_importances_)
print(model_dir.feature_importances_)



N,train_score,val_score=learning_curve(model_for,X_train_for,y_train_for,train_sizes=np.linspace(0.2,1,5),cv=3)
plt.plot(N,train_score.mean(axis=1),label='train')
plt.plot(N,val_score.mean(axis=1),label='validation')
plt.xlabel('train_sizes')
plt.legend()
plt.title('force du vent')

et les courbes d’apprentissage toujours:

Avec des courbes train égales à 1, on voit clairement que notre modèle de forêt aléatoire est « overfitté » (surapprentissage). Cependant c’est pour l’instant le modèle qui marche le mieux car en effectuant du pré-élagage sur le modèle pour réduire le train score, donc améliorer les capacités de généralisation du modèle, le test score diminue aussi, peut-être à cause d’un manque de données. Croisons toujours les twix et les bounty…

Bon on voit que les courbes d’apprentissage augmentent, mais la pente est faiblarde quand même. Va en falloir des échantillons pour faire péter les scores !

Et les résultats obtenus pour la direction puis la force du vent:

modèles:train scoretest scorebest paramsvariables utiliséestemps entrainement
arbre de décision
45%
39%max_depth=863/63rapide
forêt aléatoire99%50%max_depth=None
max_features=8
n_estimators=250
n_jobs=2
63/63long
direction du vent
modèles:train scoretest scorebest paramsvariables utiliséestemps entrainement
arbre de décision52%49%max_depth=749/63rapide
forêt aléatoire99%54%max_depth=none
max_features=8
n_estimators=250
n_jobs=2
63/63long
force du vent

Clairement la technique de bagging améliore les résultats, surtout pour la direction du vent. Par rapport à l’article précédent on voit que les scores sont nettement meilleurs qu’avec une seule station, mais il n’est pas encore temps de faire « péter les cahuètes ». Pour la force du vent c’est marrant on voit que l’arbre de décision n’utilise pas toutes les variables. Les pourcentages des train score pour les forêts aléatoires confirme le surapprentissage des modèles. En limitant l’overfitting, on baisse ici également le test score.

Pour les paramètres, ‘max_depth’ indique si on veut des arbres de décision à feuilles pures (none) ou alors tronqués à une certaine profondeur (1,2,3…). En tronquant les arbres on réduit généralement le surapprentissage. ‘max_feature’ indique le nombre de variables utilisées à la fois pour construire un arbre. ‘n_estimators’ indique le nombre d’arbres que l’on veut dans notre forêt aléatoire. Et enfin ‘n_job’ est un paramètre qui n’influe pas sur le modèle mais sur la puissance de calcul à disposition(nombre de coeurs du processeur qui calculent en même temps pour aller plus vite).

2. Ridge et bagging avec ridge

C’est partit pour ridge, on a ça:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from fonction_force import force # cette fonction permet de classer les forces de vent en catégories.


from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import learning_curve

from sklearn.preprocessing import MinMaxScaler
from sklearn.pipeline import make_pipeline

from sklearn.linear_model import RidgeClassifier

variables=pd.read_csv('C:/Users/Psychopathe/Documents/Python Scripts/meteo/station maison/mercredi11novembre/variables29.csv',sep='\t',index_col=0)
dir_test=pd.read_csv('C:/Users/Psychopathe/Documents/Python Scripts/meteo/station maison/mercredi11novembre/dir_test_29.csv',sep='\t',index_col=0)
for_test=pd.read_csv('C:/Users/Psychopathe/Documents/Python Scripts/meteo/station maison/mercredi11novembre/for_test_29.csv',sep='\t',index_col=0)

for_test.iloc[:,0]=for_test.iloc[:,0].map(lambda x:force(x))


dir_test=np.ravel(dir_test)
for_test=np.ravel(for_test)


X_train_dir,X_test_dir,y_train_dir,y_test_dir=train_test_split(variables,dir_test,test_size=0.3)
X_train_for,X_test_for,y_train_for,y_test_for=train_test_split(variables,for_test,test_size=0.3)

pipeline=make_pipeline(MinMaxScaler(),RidgeClassifier())

''' recherche du meilleur arbre de décision pour la direction du vent'''

params_dir={
     'alpha':[0.1,0.01,0.001],
     'max_iter':[1000,10000,100000],
     
        }

grille_dir=GridSearchCV(RidgeClassifier(),params_dir,cv=5)
grille_dir.fit(X_train_dir,y_train_dir)
model_dir=grille_dir.best_estimator_
print(grille_dir.best_params_)
print(model_dir.score(X_train_dir,y_train_dir))
print(model_dir.score(X_test_dir,y_test_dir))

''' recherche du meilleur arbre de décision pour la force du vent'''

params_for={
    'alpha':[0.1,0.01,0.001],
    'max_iter':[1000,10000,100000],
    }

grille_for=GridSearchCV(RidgeClassifier(),params_for,cv=5)
grille_for.fit(X_train_for,y_train_for)
model_for=grille_for.best_estimator_
print(grille_for.best_params_)
print(model_for.score(X_train_for,y_train_for))
print(model_for.score(X_test_for,y_test_for))

print(model_dir.coef_)
print(model_for.coef_)

N,train_score,val_score=learning_curve(model_dir,X_train_dir,y_train_dir,train_sizes=np.linspace(0.2,1,5),cv=5)
plt.plot(N,train_score.mean(axis=1),label='train')
plt.plot(N,val_score.mean(axis=1),label='validation')
plt.xlabel('train_sizes')
plt.legend()
plt.title('direction du vent')

Rebelotte, les courbes d’apprentissage obtenues:

Bon on constate rapidement que nos courbes sont moins belle qu’avec un arbre de décision, notamment pour la force du vent. Pour la direction on dirait qu’un palier est atteint aux alentours des 34% de score.

Si on passe ridge en bagging comme on a fait avec l’arbre de décision:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from fonction_force import force # cette fonction permet de classer les forces de vent en catégories.


from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import learning_curve

from sklearn.ensemble import BaggingClassifier

from sklearn.linear_model import RidgeClassifier

variables=pd.read_csv('C:/Users/Psychopathe/Documents/Python Scripts/meteo/station maison/mercredi11novembre/variables29.csv',sep='\t',index_col=0)
dir_test=pd.read_csv('C:/Users/Psychopathe/Documents/Python Scripts/meteo/station maison/mercredi11novembre/dir_test_29.csv',sep='\t',index_col=0)
for_test=pd.read_csv('C:/Users/Psychopathe/Documents/Python Scripts/meteo/station maison/mercredi11novembre/for_test_29.csv',sep='\t',index_col=0)

for_test.iloc[:,0]=for_test.iloc[:,0].map(lambda x:force(x))


dir_test=np.ravel(dir_test)
for_test=np.ravel(for_test)


X_train_dir,X_test_dir,y_train_dir,y_test_dir=train_test_split(variables,dir_test,test_size=0.3)
X_train_for,X_test_for,y_train_for,y_test_for=train_test_split(variables,for_test,test_size=0.3)

model=BaggingClassifier(base_estimator=RidgeClassifier(alpha=0.1,max_iter=1000),n_estimators=100)

''' recherche du meilleur arbre de décision pour la direction du vent'''

param={}

grille_dir=GridSearchCV(model,param,cv=5)
grille_dir.fit(X_train_dir,y_train_dir)
model_dir=grille_dir.best_estimator_
print(grille_dir.best_params_)
print(model_dir.score(X_train_dir,y_train_dir))
print(model_dir.score(X_test_dir,y_test_dir))

''' recherche du meilleur arbre de décision pour la force du vent'''



grille_for=GridSearchCV(model,param,cv=5)
grille_for.fit(X_train_for,y_train_for)
model_for=grille_for.best_estimator_
print(grille_for.best_params_)
print(model_for.score(X_train_for,y_train_for))
print(model_for.score(X_test_for,y_test_for))



N,train_score,val_score=learning_curve(model_for,X_train_for,y_train_for,train_sizes=np.linspace(0.2,1,5),cv=5)
plt.plot(N,train_score.mean(axis=1),label='train')
plt.plot(N,val_score.mean(axis=1),label='validation')
plt.xlabel('train_sizes')
plt.legend()
plt.title('force du vent')

Les courbes d’apprentissage:

On constate un palier pour la force du vent à environ 48,3%. Pour la direction ça monte mais la pente reste très faible.

Et maintenant le moment que vous attendez tous, une tartiflette et un clafouti aux pommes,et les scores:

modèles:train scoretest scorebest paramsvariables utiliséestemps
RidgeClassifier34%33%alpha=0.1
max_iter=1000
63/63rapide
bagging+RidgeClassifier34%34%n_estimators=100
alpha=0.1
max_iter=1000
63/63modéré
direction du vent
modèlestrain scoretest scorebest paramsvariables utiliséestemps
RidgeCLassifier49%48%alpha=0.1
max_iter=1000
63/63rapide
bagging+RidgeCLassifier48%48%n_estimators=100
alpha=0.1
max_iter=1000
63/63modéré

Ici le bagging n’apporte rien. les résultats sont moins bons que précédemment, surtout pour la direction du vent. En revanche ces modèles calculent plus vite.

3. Support vecteur machine (SVM)

On va cette fois employer une nouvelle méthode, un nouveau modèle prédictif à priori efficace pour les données arrangées de façon non linéaires. Intéressant car pour les modèles de régression linéaire j’avais essayé Polynomial_Features, pour avoir un modèle en forme de polynôme plutôt qu’en forme de fonction affine, mais j’ai trop de variables ça marche pas. Honnêtement je n’ai rien pigé à son fonctionnement réel, mais voilà ce que ça nous donne en bidouillant avec nonchalance et vacuité les hyperparamètres :

modèletrain scoretest scorebest paramstemps
SVC99%47%C: 200
gamma: 2
kernel: rbf
sur l’échelle l’inspecteur Derrick en vo non sous titrée c’est 15/20 environ
direction du vent
modèletrain scoretest scorebest paramstemps
SVC99%50%pareilpareil
force du vent

Je vous épargne le programme qui reste le même sauf pour le module importé de sklearn et le dictionnaire de paramètres qui change, plus le prétraitement des données avec MinMaxScaler cette fois pour plus d’efficacité, ce modèle appréciant les variables à la même échelle (on va également utiliser un pipeline du coup). Je n’ai pas fait de courbe d’apprentissage parce que ça faisait ramer mon pc. Les résultats sont mieux que ridge mais moins bon que la forêt aléatoire, pour un temps de calcul très long…Comme pour les forêts, SVC donne un meilleur résultat sur son test set si le modèle est overfitté (train score=100%).

4. MLP

Cette fois on va commencer à lorgner du côté des neurones virtuels avec le modèle MLP, désignés également sous le doux et sensuel sobriquet de perceptrons multicouches. En gros, et d’après mes connaissances actuelles sommaires et « à l’arrache » sur le sujet il s’agit d’un ensemble de couches de neurones empilées les unes sur les autres; à chaque couche tout les neurones sont reliés aux neurones de la couche suivante (couches denses).

Ici nos « neurones » sont en fait des fonctions mathématiques appliquant grosso merdo dans les coins en rasant les murs une somme pondérée de coefs provenant des neurones précédents, puis ensuite ils appliquent une fonction spécifique au résultat, fonction non-linéaire (RELU, sigmoide, tanh, softmax…). Le résultat est envoyé au neurone suivant.

modèletrain scoretest scorebest paramstemps
mlpclassifier50%42%une seule couche de 63 neurones
alpha: 0.001
max_iter: 1000
solver: adam
sur l’échelle l’inspecteur Derrick, c’est moins casse couilles
direction du vent
modèletrain scoretest scorebest paramstemps
mlpclassifier58%48%pareilpareil
force du vent

J’ai essayé avec plusieurs configurations, notamment en ajoutant des couches de neurones supplémentaires mais en faisant ça ça augmentait mes valeurs du train set en faisant baisser le test set. Les résultats sont inférieurs à tout les modèles précédents mais ça calcule plus vite que le modèle SVC déjà. Pareil je vous épargne le programme et la courbe d’apprentissage, pour le prétraitement ici j’ai utilisé StandardScaler.

Faire le point

Finalement pour le moment il semblerait que le modèle des forêts aléatoires soit le plus efficace pour notre jeu de données au final éparses et de natures diverses (pression, vitesse du vent, pourcentages avec l’humidité…). Il est pas trop long à entrainer, et n’a pas besoin de prétraitement alors on va s’attarder un peu sur lui. On arrive pour le moment à 49% de score pour la direction du vent et 54% pour la force du vent.On va changer notre dataset pour voir comment ce modèle va se comporter.

  1. Un dataset avec un relevé toutes les heures.

Cette fois on va « densifier » nos données météo, le nombre d’échantillons va être identique au dataset d’origine, mais les variables seront ici au nombre de 123. Avec la forêt aléatoire ça donne ça:

train scoretest scorebest paramstemps
direction du vent100%50%estimateurs: 200long
force du vent100%53%estimateurs: 200plus long

On ne constate pas de changement significatif.

2. Un dataset avec une prévision météo sur deux jours au lieu d’un.

Ici on va garder nos données toutes les 2 heures mais en demandant au modèle de prendre en conte les deux jours précédents la valeur cible au lieu d’une. Donc ce nouveau dataset aura toujours le même nombre d’échantillons mais 123 variables. En fait notre programme va aller voir plus loin dans le passé (48h au lieu de 24h) pour affiner sa prédiction météo.

train scoretest scorebest paramstemps
direction du vent100%53%estimateurs:150long
force du vent10055%estimateurs:150plus long

Il semblerait que ce soit légèrement mieux, on gagne un peu mais c’est pas l’euphorie non plus. En tout cas on dépasse les 50% pour nos deux prédictions, pas mal !

Pour la suite:

Il va falloir importer encore plus de données provenant des fichiers météo france (en définitive, le maximum), et aussi séparer notre dataset en plusieurs sous-parties selon la force du vent dans les échantillons, ou éventuellement avec d’autres variables à voir. En effet je pense qu’il est plus difficile d’avancer une prédiction fiable si les éléments, notamment la force du vent ne sont pas tranchés. Par exemple une journée avec un vent pétoleux et de l’humidité ne suffit pas à prédire la suite (passage de front, poursuite de cette configuration occluse foireuse…) En fait il va peut-être falloir introduire des pourcentages de fiabilité sur nos prévisions en rapport avec l’état de certaines variables dans notre échantillon…Un peu comme météo france en somme. Il va peut-être aussi falloir ajouter une variable supplémentaire de « temps », pour indiquer à l’algo à quelle période de l’année on est afin d’affiner les résultats (plus de dépressions en hiver qu’en été). On a utilisé jusqu’à maintenant le temps pour agencer et traiter nos données, mais pas vraiment pour affuter la prévision.

Jusqu’à maintenant on a utilisé des outils de machine learning, il va falloir aussi tester si possible d’autres outils comme keras ou tensorflow pour voir ce que ça donne (deep learning). Putain on est pas sortit de l’auberge.

Ps: si besoin je peux mettre en lien les fichiers csv modifiés, prêt à l’emploi.

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.