Apprendimento automatico con XGBoostScopo
Ecco un tentativo della mia prima applicazione creata con app-builder utilizzando la connessione tra JMP e Python per gestire un complesso algoritmo di machine learning.
Lo scopo di questa app è avviare un'interfaccia utente grafica scritta in jsl e connettere tale interfaccia con l'API di apprendimento automatico "XGBoost".
Come usare
Ho implementato la possibilità di lavorare su 3 tipi di schemi di validazione: holdout / validazione incrociata / ricerca in griglia. Sia le regressioni che le classificazioni sono state sviluppate su pochi obiettivi e metriche classiche.
Al termine della formazione, viene fornito un report con il valore delle metriche sia sul set di training/convalida che su media/sviluppo standard per la convalida incrociata. Nel caso di un addestramento alla ricerca su griglia, il report viene fornito con i migliori risultati degli iperparametri e possiamo scegliere di utilizzare l'arresto anticipato. È anche possibile esportare il modello Python per prevedere nuovi dati senza addestrare nuovamente il modello (ma dovrebbe essere fatto in un ambiente Python)
Dovresti quindi verificare che JMP possa gestire quel collegamento con Python prima di utilizzare l'app...




Per la nuova versione 2024:
Molti aggiornamenti erano necessari con gli aggiornamenti delle librerie Python, quindi ho colto l'occasione per aggiungere funzionalità che mi mancavano nell'uso pratico e per correggere alcuni bug...
- Ora forzo i nomi delle colonne ad avere un certo schema per evitare qualsiasi conflitto tra python/JMP (cancellerò tutti i caratteri speciali, la punteggiatura, gli spazi) e approfitto della nuova possibilità introdotta da JMP 16 per forzare il formato decimale con punti da evitare alcuni incidenti che ho avuto in precedenza.
- Ora sto anche controllando che le risposte siano nel formato corretto per problemi di classificazione (deve essere numerico e iniziare da 0 visto le modifiche apportate a xgboost, presumibilmente legate a modifiche numpy) e sto correggendo il problema della classe sulle risposte binarie ciò potrebbe verificarsi in alcuni casi con la prima versione del componente aggiuntivo.
- Aggiunta una casella di controllo per consentirti di conservare il treno generato e testare i set di dati in modo da poterli esportare come CSV e lavorare sulla stessa base quando vuoi mescolare questo componente aggiuntivo con Python classico (e quindi altri algoritmi ML per un divertimento ancora maggiore ^^ ).

- Aggiunta dell'iperparametro 'Gamma' (noto anche come 'min_split_loss', ovvero un controllo del grado di regolarizzazione dell'albero, specificando la riduzione minima della funzione di perdita richiesta per giustificare l'ulteriore frazionamento di un nodo).

- Ora visualizzo sistematicamente gli iperparametri del modello dopo l'adattamento, nello stesso ordine dell'add-in, per rendere più semplice l'associazione di questi iperparametri alle prestazioni del modello e anche per facilitarne la copia nell'add-in (quando si passa dalla ricerca nella griglia per la convalida incrociata, ad esempio).

- Ora recupero l'elenco delle funzionalità utilizzate dal modello addestrato, normalizzato da F-Score, e visualizzo quelle la cui normalizzazione è maggiore di 0,20, quindi le visualizzo nei log in un formato che può essere direttamente copiato e incollato in JMP (e quindi più facilmente aggiunto ad un'altra analisi). Questo elenco è ordinato in base al valore F-Score decrescente.

- Installazione di un output matplotlib in modo che l'importanza delle funzionalità del modello possa ora essere visualizzata direttamente senza dover esportare e quindi importare in un ide python (questo era previsto nella mia versione iniziale ma JMP15 si bloccava sistematicamente non appena matplotlib veniva importato, sembra essere stato risolto in JMP 17 ma non l'ho testato in JMP 16), il grafico si adatta al numero di funzioni visualizzate (dimensione del carattere e margine).
Esempio su un set di dati classico ("prezzi delle case di Boston": https://www.kaggle.com/competitions/home-data-for-ml-course/data 

Configurazione di sistema
Componente aggiuntivo sviluppato e testato utilizzando la seguente configurazione di sistema:
JMP17
Python 3.11 o 3.12 con numpy, pandas, pathlib, multiprocesso, scikit-learn, xgboost
Testato utilizzando il set di dati classico (Titanic, case di Boston,...)

Modellazione predittiva e data miningRe: Machine Learning con XGBoost in un componente aggiuntivo JMP (app JMP + python)Ok Franck
grazie per la tua risposta.
Come già detto ero solo curioso di sapere. Ora è chiaro.
Rgds.Felice
Re: Machine Learning con XGBoost in un componente aggiuntivo JMP (app JMP + python)Ciao Felice e grazie per il tuo feedback!
Non ricordo esattamente quale fosse il problema, ma ho avuto un problema con l'elaborazione di dati non numerici durante il trasferimento di Python.
E a causa della mancanza di segnalazioni di errori non appena JMP esegue il codice Python, non sono riuscito a identificare la causa principale e risolverla. Il codice dello script python per categorial era ok, anche il codice JMP ma il codice JMP quindi il codice python stava bloccando lo script ...
Un giorno dovrò provare a ripensarci!
Devi solo ricodificare i valori per esempio: yes = 1 e no = 2 oppure setosa = 1, versicolor = 2, virginica =3,... È un po 'ingombrante ma era per aggirare questo bug
Re: Machine Learning con XGBoost in un componente aggiuntivo JMP (app JMP + python)Ciao Franco. I tuoi componenti aggiuntivi sono davvero ben fatti.
Solo una curiosità. Perché quando scelgo l'attività di classificazione il tipo di variabile di risposta deve essere numerico? Mi aspettavo una variabile categoriale (cattiva vs buona, linea di base vs esperimento, gatto vs cane ecc. ecc.)
Rgds.Felice
Re: Machine Learning con XGBoost in un componente aggiuntivo JMP (app JMP + python)Nessun problema Francesco. È un grande contributo, grazie per la condivisione.
Re: Machine Learning con XGBoost in un componente aggiuntivo JMP (app JMP + python)Grazie!
Sì, spero anche che il supporto di Python venga migliorato nel tempo.
Per l'interfaccia, scusa se ho realizzato questo addin quasi interamente nel mio tempo libero ma con la licenza di JMP pagata dalla mia azienda, ritengo che la pubblicazione del codice sorgente debba essere convalidata dal mio datore di lavoro che desidera che questo codice sorgente rimanga privato.
Re: Machine Learning con XGBoost in un componente aggiuntivo JMP (app JMP + python)Questo è fantastico! Grazie per averlo condiviso*
Per quanto riguarda Python in Windows, Anaconda con Python 3.6 funziona immediatamente con JMP 15, ma è necessario aggiornare tutti i pacchetti poiché è un pacchetto di 2 anni. Spero che JMP migliori il proprio supporto Python nelle prossime versioni.
(*nota) L'interfaccia che hai creato può essere utilizzata per altre API Python. Hai pubblicato anche il codice sorgente?
Saluti.
Re: Machine Learning con XGBoost in un componente aggiuntivo JMP (app JMP + python)Ciao Rut
Sono molto dispiaciuto di non avere idea di cosa stia succedendo: sospettavo qualche problema con il modo in cui Mac OS gestisce la directory in modo diverso rispetto a Windows, ma il crash si trova nella parte di Python e non prima. Inoltre l'arresto anomalo si verifica mentre non hai utilizzato l'opzione di esportazione del file
Forse è correlato a un problema con il pacchetto come dici tu. Proverò ad aggiornare i miei pacchetti il prima possibile per verificare se gli stessi pacchetti su Windows 10 sono ancora OK o meno.
Grazie per aver provato il mio componente aggiuntivo! 
Franco
Re: Machine Learning con XGBoost in un componente aggiuntivo JMP (app JMP + python)Grazie per aver esaminato il mio problema, @Franck_R .La mia installazione di Python funziona con JMP per altro codice (incluso il codice di test che hai suggerito), ma potrebbe esserci ancora un problema con un pacchetto o qualche altro componente mancante necessario per il tuo componente aggiuntivo che non ho ancora scoperto. Sono totalmente perplesso per ora. Quando ne avrò la possibilità, proverò a configurarlo su un computer Windows per fare un altro tentativo.
Grazie ancora per averlo pubblicato nella community: è un'applicazione molto utile!
Re: Machine Learning con XGBoost in un componente aggiuntivo JMP (app JMP + python)Lo stesso set di dati senza problemi sul mio computer:

Re: Machine Learning con XGBoost in un componente aggiuntivo JMP (app JMP + python)CIAO,
Sì, il problema è davvero nella parte di Python, mi dispiace per quello ...
È strano perché il codice Python non è stato eseguito affatto: il codice è andato in crash prima del comando "try"! Non aggiungo mai quel tipo di incidente...
Ma è complicato eseguire il debug del registro perché JMP non scrive alcun messaggio di errore di Python ... lancia semplicemente il codice Python senza spiegazioni ... Quando usiamo python con JMP e python incontra un problema non c'è un codice di errore esplicito: ho dovuto sviluppare tutto il codice python al di fuori di JMP e quindi integrare quel codice in JMP per questo motivo ...
Questo set di dati è ben gestito sul mio computer ma lavoro su Windows 10 e con Python 3.7
La prima cosa da verificare è che JMP 15.1 sia in grado di gestire Python 3.8 Non sono davvero sicuro che sia così (ci sono state alcune difficoltà con Python 3.7, ad esempio, vedi https://community.jmp.com/t5/Discussions/JMP-14-Python-abilities-working-Im-confused/td-p/184515
prova ad eseguire il codice di esempio nell'indice di scripting:
Nomi Predefinito A Qui( 1 );
Python Init();
Invia Python(
"\[
str = 'La veloce volpe bruna salta sopra il cane pigro';
un = 200;
]\"
);
getStr = Python Get( str );
getNum = Python Get( a );
Mostra( getStr, getNum );
Termine Python();
Quindi, c'è qualche valore mancante nel tuo set di dati? (Non controllo il valore mancante nel set di dati e può bloccarsi a causa di ciò se si tratta di un set di dati di Boston rielaborato con alcuni valori mancanti)
Non sono nemmeno sicuro che il mio codice possa gestire Mac OS perché non ho modo di verificarlo e l'integrazione di Python può essere forse leggermente diversa da Windows ...
Re: Machine Learning con XGBoost in un componente aggiuntivo JMP (app JMP + python)Grazie per averlo reso disponibile! Sto tentando di eseguirlo sui dati di Boston Housing, leggermente adattati per includere una colonna di convalida appropriata e una colonna ID numerico e con la variabile "chas" come indicatore numerico. (Vedi screenshot qui sotto.) Sto eseguendo JMP Pro 15.1 su MacOS 10.15.3 con Python 3.8.2 e numpy 1.18.2, pandas 1.0.3, scikit-learn 0.23.1 e XGBoost 1.1.0. Sto copiando il registro qui sotto. Ovviamente qualcosa funziona per un po', ma poi Python va in crash. Alla fine, ricevo l'avviso che "Send Expects Scriptable Object in accesso o valutazione di 'Invia'". Immagino che questo errore si verifichi perché Python si è bloccato e non ha creato l'oggetto da inviare.
Qualche idea su cosa potrebbe andare storto? Non sono un esperto di scripting, ma oltre a questa debolezza, non capisco l'output francese nel registro;)
Grazie!
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'


Ri: Apprendimento automatico con XGBoostCIAO
Ho aggiornato il componente aggiuntivo con compatibilità con le nuove versioni di Python + nuove funzionalità + correzioni di bug
Ri: Apprendimento automatico con XGBoostPosso commentare il motivo per cui hai avuto arresti anomali con matplotlib. Sia il loop degli eventi della finestra principale di JMP che il loop degli eventi della finestra principale di matplotlib si scontrano. Poiché la libreria condivisa Python viene caricata nello spazio di elaborazione di JMP, JMP dispone già di una finestra principale. Matplotlib chiamato con i soliti metodi ritiene di avere il ciclo della finestra principale. Dipende interamente dal backend matplolib scelto. Dopo 14 abbiamo forzato il backend maptplotlib sul backend "AGG" non interattivo ed è completamente utilizzabile semplicemente dicendo a matplotlib di salvare la figura anziché mostrarla. L'altro problema che potresti aver riscontrato è che JMP non si bloccava in tutti i casi ma si chiudeva. L'ultima finestra di matplotib chiusa stava chiamando un'uscita di livello C () al di fuori del controllo di JMP. JMP 18.0 è un po' più indulgente, se consente matplotlib su Windows senza forzarlo sul backend AGG, ma su Mac il backend Cocoa predefinito si blocca comunque, ho una segnalazione di bug aperta con gli sviluppatori matplotlib. Sul Mac ho avuto un certo successo con un backend PySide o PyQt, ma è ancora incostante. Il modo migliore per chiamare matplotlib è salvare la figura come immagine.
Ri: Apprendimento automatico con XGBoostCiao Paul,
Grazie per il seguito e le spiegazioni! Sono contento di vedere che l'integrazione con Python continua in JMP 18...