Apprentissage automatique avec XGBoostBut
Voici une tentative de ma première application construite avec app-builder utilisant la connexion entre JMP et Python pour gérer un algorithme d'apprentissage automatique complexe.
Le but de cette application est de lancer une interface utilisateur graphique écrite en jsl et de connecter cette interface à l'API d'apprentissage automatique « XGBoost ».
Comment utiliser
J'ai implémenté la possibilité de travailler sur 3 types de schéma de validation : holdout / validation croisée / recherche par grille. Les régressions et les classifications ont été développées sur quelques objectifs et métriques classiques.
À la fin de la formation, un rapport est fourni avec la valeur des métriques sur l'ensemble d'entraînement/validation ou sur le développement moyen/standard pour la validation croisée. Dans le cas d'un entraînement à la recherche de grille, le rapport est fourni avec les meilleurs résultats d'hyperparamètres et nous pouvons choisir d'utiliser un arrêt anticipé. Il est également possible d'exporter le modèle python pour prédire de nouvelles données sans réentraîner le modèle (mais cela doit être fait dans un environnement python)
Vous devez ensuite vérifier que JMP peut gérer ce lien avec Python avant d'utiliser l'application...




Pour la nouvelle version 2024 :
De nombreuses mises à jour ont été nécessaires avec les mises à jour des librairies python, j'en ai donc profité pour ajouter des fonctionnalités qui me manquaient en pratique et pour corriger pas mal de bugs...
- Je force désormais les noms de colonnes à avoir un certain modèle pour éviter tout conflit entre python/JMP (j'efface tous les caractères spéciaux, ponctuation, espaces) et je profite de la nouvelle possibilité introduite par JMP 16 pour forcer le format décimal avec des points pour éviter certains crashs que j'ai eu auparavant.
- Je vérifie aussi maintenant que les réponses sont au bon format pour les problèmes de classification (elles doivent être numériques et commençant à 0 depuis les modifications apportées à xgboost, vraisemblablement liées aux modifications numpy) et je corrige le problème de classe sur les réponses binaires cela pourrait se produire dans certains cas avec la première version du complément.
- Ajout d'une case à cocher pour vous permettre de conserver les jeux de données d'entraînement et de test générés afin de pouvoir les exporter au format csvs et travailler sur les mêmes bases lorsque vous souhaitez mélanger ce complément avec du python classique (et donc d'autres algos ML pour encore plus de plaisir ^^ ).

- Ajout de l'hyperparamètre 'Gamma' (alias 'min_split_loss', c'est à dire une vérification du degré de régularisation de l'arbre, en précisant la réduction minimale de la fonction de perte requise pour justifier le fractionnement supplémentaire d'un nœud).

- J'affiche désormais systématiquement les hyperparamètres du modèle après ajustement, dans le même ordre que le complément, pour faciliter l'association de ces hyperparamètres aux performances du modèle et également pour faciliter leur recopie dans le complément (lorsque vous passez de la recherche par grille pour une validation croisée par exemple).

- Je récupère maintenant la liste des fonctionnalités utilisées par le modèle entraîné, normalisées par F-Score, et j'affiche celles dont la normalisation est supérieure à 0,20, puis je l'affiche dans les logs dans un format directement copié-collé dans JMP (et donc plus facilement ajouté à une autre analyse). Cette liste est triée par valeur F-Score décroissante.

- Installation d'une sortie matplotlib pour que l'importance des fonctionnalités du modèle puisse désormais être affichée directement sans avoir à exporter puis importer dans une ide python (cela était envisagé dans ma version initiale mais JMP15 plantait systématiquement dès l'importation de matplotlib, cela semble avoir été résolu dans JMP 17 mais je ne l'ai pas testé dans JMP 16), le graphique s'adapte au nombre de fonctionnalités affichées (taille de police et marge).
Exemple sur un jeu de données classique (« Prix de l'immobilier à Boston ») : https://www.kaggle.com/competitions/home-data-for-ml-course/data 

Configuration du système
Complément développé et testé en utilisant la configuration système suivante :
JMP17
Python 3.11 ou 3.12 avec numpy, pandas, pathlib, multiprocess, scikit-learn, xgboost
Testé sur un jeu de données classique (Titanic, Boston Houses,...)

Modélisation prédictive et exploration de donnéesRe : Apprentissage automatique avec XGBoost dans un complément JMP (application JMP + python)D'accord Franck
Merci pour votre réponse.
Comme déjà mer, j'étais juste curieux de savoir. Maintenant c'est clair.
Rgds.Félix
Re : Apprentissage automatique avec XGBoost dans un complément JMP (application JMP + python)Bonjour Felice et merci pour votre commentaire !
Je ne me souviens pas exactement quel était le problème, mais j'ai eu un problème pour traiter les données non numériques lors du transfert de python.
Et à cause de l'absence de rapport d'erreur dès que JMP exécute du code python, je n'ai pas réussi à identifier la cause première et à la résoudre. Le code du script python pour categorial était correct, le code JMP aussi mais le code JMP puis le code python plantaient le script...
Il faudra un jour que j'essaye de m'y remettre !
Il suffit de recoder les valeurs par exemple : oui = 1 et non = 2 ou setosa = 1, versicolor = 2, virginica =3,... C'est un peu lourd mais c'était pour contourner ce bug
Re : Apprentissage automatique avec XGBoost dans un complément JMP (application JMP + python)Ciao Franck. Votre addins est vraiment bien fait.
Juste une curiosité. Pourquoi lorsque je choisis la tâche de classification, le type de variable de réponse doit être numérique ? Je m'attendais à une variable catégorielle (mauvais vs bon, ligne de base vs expérience, chat vs chien etc etc..)
Rgds.Félix
Re : Apprentissage automatique avec XGBoost dans un complément JMP (application JMP + python)Pas de problème Franck. C'est une belle contribution, merci pour le partage.
Re : Apprentissage automatique avec XGBoost dans un complément JMP (application JMP + python)Merci!
Oui, j'espère aussi que le support de Python s'améliorera avec le temps.
Pour l'interface, désolé j'ai réalisé cet addin presque entièrement sur mon temps libre mais avec la licence JMP payée par mon entreprise, je considère que la publication du code source doit être validée par mon employeur qui souhaite que ce code source reste privé.
Re : Apprentissage automatique avec XGBoost dans un complément JMP (application JMP + python)C'est bien! Merci de le partager*
En ce qui concerne Python sous Windows, Anaconda avec Python 3.6 fonctionne avec JMP 15, mais vous devez mettre à jour tous les packages car il s'agit d'un package de 2 ans. J'espère que JMP améliorera son support Python dans les prochaines versions.
(*note) L'interface que vous avez construite peut être utilisée pour d'autres API Python. Avez-vous également publié le code source ?
Salutations.
Re : Apprentissage automatique avec XGBoost dans un complément JMP (application JMP + python)Salut Ruth
Je suis vraiment désolé, je n'ai aucune idée de ce qui se passe: j'ai soupçonné un problème avec la façon dont Mac OS gère le répertoire différemment de Windows, mais le plantage se situe dans la partie python et pas avant. De plus le plantage se produit alors que vous n'avez pas utilisé l'option d'exportation de fichier
Peut-être est-ce lié à un problème de package comme vous le mentionnez. Je vais essayer de mettre à jour mes packages dès que possible pour vérifier si les mêmes packages sur Windows 10 sont toujours OK ou non.
Merci d'avoir essayé mon addin ! 
Franck
Re : Apprentissage automatique avec XGBoost dans un complément JMP (application JMP + python)Merci de vous être penché sur mon problème, @Franck_R .Mon installation Python fonctionne avec JMP pour d'autres codes (y compris le code de test que vous avez suggéré), mais il peut toujours y avoir un problème avec un package ou un autre composant manquant nécessaire pour votre complément que je n'ai pas encore découvert. Je suis totalement paumé pour l'instant. Quand j'en aurai l'occasion, j'essaierai de le configurer sur une machine Windows pour faire un autre essai.
Merci encore d'avoir mis cela dans la communauté - c'est une application très utile !
Re : Apprentissage automatique avec XGBoost dans un complément JMP (application JMP + python)Le même jeu de données sans problème sur mon ordinateur :

Re : Apprentissage automatique avec XGBoost dans un complément JMP (application JMP + python)Salut,
Oui le problème est bien dans la partie python désolé pour ça...
C'est bizarre car le code python n'a pas du tout été exécuté : le code a planté avant la commande "try" ! Je n'ajoute jamais ce genre de crash....
Mais il est difficile de déboguer votre journal car JMP n'écrit aucun message d'erreur de python... il lance simplement le code python sans explications... Lorsque nous utilisons python avec JMP et que python rencontre un problème, il n'y a pas de code d'erreur explicite : j'ai dû développer tout le code python en dehors de JMP, puis intégrer ce code dans JMP à cause de cela...
Ce jeu de données est bien géré sur mon ordinateur mais je travaille sur windows 10 et avec python 3.7
La première chose à vérifier est que JMP 15.1 peut gérer python 3.8 Je ne suis vraiment pas sûr que ce soit le cas (il y a eu quelques difficultés avec python 3.7 par exemple voir https://community.jmp.com/t5/Discussions/JMP-14-Python-abilities-working-Im-confused/td-p/184515
essayez d'exécuter l'exemple de code dans l'index de script :
Noms par défaut à ici( 1 );
Init Python();
Soumission Python(
"\[
str = 'Le renard brun rapide saute par-dessus le chien paresseux';
un = 200 ;
]\"
);
getStr = Python Get( str );
getNum = Python Get( a );
Afficher( getStr, getNum );
Terme Python();
Alors, y a-t-il une valeur manquante dans votre jeu de données ? (Je ne vérifie pas la valeur manquante dans l'ensemble de données et cela peut planter à cause de cela s'il s'agit d'un ensemble de données boston retravaillé avec des valeurs manquantes)
Je ne suis pas sûr non plus que mon code puisse gérer Mac OS car je n'ai aucun moyen de vérifier cela et l'intégration de python peut être peut-être un peu différente de celle de Windows ...
Re : Apprentissage automatique avec XGBoost dans un complément JMP (application JMP + python)Merci de l'avoir rendu disponible! J'essaie de l'exécuter sur les données de Boston Housing, légèrement ajustées pour inclure une colonne de validation appropriée et une colonne d'ID numérique et avec la variable "chas" comme indicateur numérique. (Voir la capture d'écran ci-dessous.) J'exécute JMP Pro 15.1 sur MacOS 10.15.3 avec Python 3.8.2 et numpy 1.18.2, pandas 1.0.3, scikit-learn 0.23.1 et XGBoost 1.1.0. Je copie le journal ci-dessous. De toute évidence, quelque chose fonctionne pendant un moment, mais ensuite Python se bloque. En fin de compte, je reçois l'avertissement "Envoyer attend un objet inscriptible lors de l'accès ou de l'évaluation de 'Envoyer'." J'imagine que cette erreur se produit parce que Python s'est écrasé et n'a pas créé l'objet à envoyer.
Des idées sur ce qui pourrait mal se passer ? Je ne suis pas un expert en script, mais en plus de cette faiblesse, je ne comprends pas une partie de la sortie française dans le journal 
Merci!
Ruth
"*** DEBUG Report: Start"
"******* Fonction update OK"
"**** Valeurs initialisées"
2
"**** OK avant lancement algo"
"***** La table de travail est:"
DataTable("Boston Housing.jmp")
/Library/Frameworks/Python.framework/Versions/3.8/lib/python38.zip
/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8
/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/lib-dynload
/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages
/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/aeosa
/**********/
# Partie import des biblios Python
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import mean_squared_error
from xgboost import XGBRegressor
from joblib import dump, load
from pathlib import Path
# Optionnel
#from xgboost import plot_tree
# On affiche pas les warnings python
import warnings
warnings.simplefilter("ignore")
try:
# On créé des DataFrame avec les Data Table JMP
data_frame_train = pd.DataFrame(dt_train)
data_frame_valid = pd.DataFrame(dt_valid)
data_frame_test = pd.DataFrame(dt_test)
# On récupère l'index du DF avec Id pour le réutiliser dans la génération du dataframe de la réponse
Id_train = data_frame_train[colId]
Id_valid = data_frame_valid[colId]
Id_test = data_frame_test[colId]
# On fixe l'index du DF avec Id
data_frame_train.set_index(colId)
data_frame_valid.set_index(colId)
data_frame_test.set_index(colId)
# On conserve la table train non modifiée
data_frame_train_initial = pd.DataFrame(dt_train)
# On fixe l'index du DF avec Id
data_frame_train_initial.set_index(colId)
# On fixe le y
y_train = data_frame_train[colY]
y_valid = data_frame_valid[colY]
y_test = data_frame_test[colY]
# On fixe les facteurs: ce sont ici les colonnes récupérées de la liste des colonnes de JMP donc les features contenus dans liste_colonne
X_train = data_frame_train[liste_colonne]
X_valid = data_frame_valid[liste_colonne]
X_test = data_frame_test[liste_colonne]
# MODELISATION
# On définit le modèle comme étant un régresseur XGBoost
# my_model = XGBRegressor(n_estimators=100, learning_rate=0.05, random_state=0)
#param_dist = {'n_estimators':2,'learning_rate'=0.05,'random_state'=0 }
# ATTENTION: le transfert de variable est piégeux car un integer est converti en decimal
# Or dans cette list de paramètre XGBoost ne tolère pas tout le temps des décimals, il faut donc convertir en Integer avec int()
# Conversion des paramètres:
Int_Nb_Iterations = int(Nb_Iterations)
Int_Max_Depth = int (Max_Depth)
Int_Min_Child = int (Min_Child)
# Assignation des paramètres
max_depth = Int_Max_Depth
min_child_weight = Int_Min_Child
subsample = Sub_Sample
colsample_bytree = Col_Sample
objective = Objective
num_estimators = Int_Nb_Iterations
learning_rate = Learning_Rate
my_model = XGBRegressor(max_depth=max_depth,min_child_weight=min_child_weight,subsample=subsample,colsample_bytree=colsample_bytree,objective=objective,n_estimators=num_estimators,learning_rate=learning_rate)
# On fitte le modèle
my_model.fit(X_train, y_train)
# On récupère les prédictions sur le set de la table train partie validation
predictions_sur_train_XGBoost = my_model.predict(X_train)
predictions_sur_validation_XGBoost = my_model.predict(X_valid)
# Calculate Score
#score_train = mean_absolute_error(predictions_sur_train_XGBoost, y_train)
#score_valid = mean_absolute_error(predictions_sur_validation_XGBoost, y_valid)
if Type_Score == 'MAE': score_train = mean_absolute_error(predictions_sur_train_XGBoost, y_train); score_valid = mean_absolute_error(predictions_sur_validation_XGBoost, y_valid)
elif Type_Score == 'RMSE': score_train = mean_squared_error(predictions_sur_train_XGBoost, y_train) ; score_valid = mean_squared_error(predictions_sur_validation_XGBoost, y_valid)
else: print("toto")
# Export prévisions sur table train et validate
output_train_XGBoost = pd.DataFrame({colY: predictions_sur_train_XGBoost,colId : Id_train})
output_validation_XGBoost = pd.DataFrame({colY: predictions_sur_validation_XGBoost, colId : Id_valid })
# On concatene les dataframe train et valid afin de réentrainer le modèle sur l'ensemble des données pour prédire le y_test
X_full = pd.concat([X_train, X_valid])
y_full = pd.concat([y_train, y_valid])
# On réentraine le modèle sur train + validate et on l'exporte sur test
my_model.fit(X_full, y_full)
predictions_sur_test_XGBoost = my_model.predict(X_test)
output_test_XGBoost = pd.DataFrame({colY: predictions_sur_test_XGBoost,colId : Id_test})
# ------------------------- Essais de sortie graphique: plantage car JMP 15.1 n'est pas fonctionnel
# fit = alg.fit(dtrain[ft_cols].values, dtrain['y'].values)
# ft_weights = pd.DataFrame(fit.feature_importances_, columns=['weights'], index=ft_cols)
# model = xgb.train(params, d_train, 1000, watchlist)
# fig, ax = plt.subplots(figsize=(12,18))
# xgb.plot_importance(model, max_num_features=50, height=0.8, ax=ax)
# plt.show()
# ft_weights = my_model.feature_importances_
#import matplotlib.pylab as plt
#from matplotlib import pyplot
#from xgboost import plot_importance
#plot_importance(model, max_num_features=10) # top 10 most important features
#plt.show()
# -------------------------
if int(File_Save_Check) == 1:
data_folder = Path(File_Save_Directory)
file_to_save = data_folder / File_Save_Name
dump(my_model, file_to_save)
except:
print("python has crashed check your parameters")
/**********/
Send Expects Scriptable Object in access or evaluation of 'Send'


Re : Apprentissage automatique avec XGBoostSalut
J'ai mis à jour le complément avec une compatibilité avec les nouvelles versions de Python + nouvelles fonctionnalités + corrections de bugs
Re : Apprentissage automatique avec XGBoostJe peux commenter la raison pour laquelle vous avez eu des plantages avec matplotlib. La boucle d'événements de la fenêtre principale de JMP et la boucle d'événements de la fenêtre principale de matplotlib entrent en conflit. Étant donné que la bibliothèque partagée Python est chargée dans l'espace de processus de JMP, JMP dispose déjà d'une fenêtre principale. Matplotlib appelé par les méthodes habituelles pense qu'il possède la boucle de la fenêtre principale. Cela dépend entièrement du backend matplolib choisi. Après 14, nous avons forcé le backend maptplotlib vers le backend non interactif 'AGG' et il est entièrement utilisable en disant simplement à matplotlib de sauvegarder la figure plutôt que de l'afficher. L'autre problème que vous avez peut-être constaté est que JMP ne plante pas dans tous les cas, mais se ferme. La dernière fenêtre de matplotib fermée appelait un exit() de niveau C hors du contrôle de JMP. JMP 18.0 est un peu plus indulgent, s'il autorise matplotlib sur Windows sans le forcer vers le backend AGG, mais sur Mac, le backend Cocoa par défaut plante toujours, j'ai un rapport de bug ouvert avec les développeurs matplotlib. Sur Mac, j'ai eu un certain succès avec un backend PySide ou PyQt, mais c'est toujours un hasard. La meilleure façon d’appeler matplotlib est de sauvegarder la figure sous forme d’image.
Re : Apprentissage automatique avec XGBoostSalut Paul,
Merci pour le suivi et les explications ! Heureux de voir que l'intégration avec python se poursuit dans JMP 18...