Bonjour à tous,
J'ai un script JSL qui crée une table de données, et j'y ai ajouté un bloc de code Python que je souhaite transmettre pour effectuer des prédictions à l'aide d'un modèle de machine learning entraîné. Avant le bloc de code Python, la table de données est accessible et s'ouvre même dans JMP. Cependant, après le bloc de code Python, lorsque j'essaie d'accéder aux prédictions du modèle de réseau neuronal basé sur la table de données via « Show(preds_df) », j'obtiens l'erreur « Nom non résolu : preds_df lors de l'accès ou de l'évaluation de 'preds_df' ». J'utilise JMP Pro 17. Voici mon bloc de code pour révision.
<
Clear Log();
Clear Symbols();
Names Default To Here( 1 );
// Define the list of options for the dropdown
SITE = {"SITE_1", "SITE_2"};
MODELS = {"NN_MODEL", "RNN_MODEL"};
PythonConnection = Python Connect();
conn = PythonConnection << Is Connected;
PythonConnection << Send( dt);
close(dt);
PythonConnection << Send(MODELS);
PythonConnection << Execute("
import pandas as pd
from sklearn.preprocessing import StandardScaler
import torch
import pickle
import numpy as np
// Model Selection
if 'NN_MODEL' in MODELS:
model = 'NN_MODEL'
else:
model = 'RNN_MODEL'
# Extract categorical and numerical features from data
categorical_features = ['NAME', 'COUNTRY', 'SCHOOL']
numerical_features = ['AGE', 'SIZE', 'HEIGHT', 'WEIGHT']
# One-Hot encoding for categorical features in place
process_df = pd.get_dummies(dt, columns=categorical_features, drop_first=True)
# Normalize numerical features
scaler = StandardScaler()
new_df[numerical_features] = scaler.fit_transform(process_df[numerical_features])
# Exclude bin columns from the model input
B_cols = ['B1', 'B8', 'B9', 'B10']
B_columns = [col for col in B_cols if col in process_df.columns]
input_df = process_df.drop(B_columns, axis=1)
labels = process_df[B_cols]
ids = process_df[B_cols].index
# Load the trained model based on user selection
if model == 'NN_MODEL':
model_path = '.\\nn_model.pth'
model = torch.load(model_path)
model.eval()
# Convert DataFrame to tensor
in_tensor = torch.tensor(input_df.values, dtype=torch.float32)
# Predict using the model
with torch.no_grad():
nn_preds = model(in_tensor)
nn_preds = torch.round(nn_preds).to(torch.int).numpy()
nn_preds = np.clip(nn_preds, a_min=0, a_max=None)
preds_df = pd.DataFrame(nn_preds.numpy(), index=ids, columns=labels)
else:
model_path = '.\\rnn_model.pkl'
with open(model_path, 'rb') as file:
model = pickle.load(file)
rnn_preds = model.predict(input_df)
rnn_preds = np.clip(rnn_preds, a_min=0, a_max=None)
preds_df = pd.DataFrame(rnn_preds, index=ids, columns=labels)
"
);
Show(preds_df)
>
En regardant très rapidement, preds_df n'est qu'un dataframe pandas, pas une table JMP, vous ne pouvez donc pas y accéder depuis JMP.
Essayez ceci à la fin de votre script JSL :
dt = Python Get( preds_df );
dt << New Data View;
JMP 18 peut également exécuter des scripts Python de manière native, il n'est donc pas nécessaire de les intégrer dans des scripts JSL.
J'ai reçu « L'envoi attend un objet scriptable lors de l'accès ou de l'évaluation de l'envoi, « dt » << /*###*/Nouvelle vue de données/*###*/ »
Vous pouvez. Je ne me souviens pas si JMP17 est capable de le faire directement, mais vous pouvez par exemple passer par un fichier .csv : créez un fichier .csv à partir du dataframe pandas, puis transmettez ce chemin à JMP et ouvrez-le.
Premièrement, la syntaxe de << Execute() est incorrecte. Voir l'exemple dans l'index des scripts. Le premier paramètre de Execute est une liste JSL d'entrées, suivie d'une liste JSL de variables de sortie, puis du script, puis du paramètre facultatif echo(1 ou 0).
Le script devrait être délimité par les marqueurs de chaîne « bruts » JSL « \[script ici ] » afin de préserver les espaces et les fins de ligne. Je suis surpris que vous n'obteniez pas d'erreur de syntaxe, mais je constate la même absence d'erreur sur la version 19… Je suis en train de vérifier. Pour moi, l'affichage de preds_df s'est simplement affiché.
dt = .;
qui manque. Cela signifie donc bien sûr :
dt << Nouvelle vue de données
Génère une erreur car dt (manquant) n'est pas scriptable.
Le code ci-dessous reproduit votre problème.
conn = Python Connect();
conn << Get Version();
conn << Execute( "
import pandas as pd
import numpy as np
pandas_df = pd.DataFrame(
{
"A": 1.0,
"B": pd.Timestamp("20130102"),
"C": pd.Series(1, index=list(range(4)), dtype="float32"),
"D": np.array([3] * 4, dtype="int32"),
"E": pd.Categorical(["test", "train", "test", "train"]),
"F": "foo",
}
)
print(pandas_df)
]\", echo(1) );
dt = Python Get(pandas_df);
show(dt);
dt << New Data View;
Ce code s'exécute comme prévu
conn = Python Connect();
conn << Get Version();
conn << Execute( {},{},"\[
import pandas as pd
import numpy as np
pandas_df = pd.DataFrame(
{
"A": 1.0,
"B": pd.Timestamp("20130102"),
"C": pd.Series(1, index=list(range(4)), dtype="float32"),
"D": np.array([3] * 4, dtype="int32"),
"E": pd.Categorical(["test", "train", "test", "train"]),
"F": "foo",
}
)
print(pandas_df)
]\", echo(1) );
dt = Python Get(pandas_df);
show(dt);
dt << New Data View;
Il convient de noter que JMP 17 est la dernière version à utiliser Python depuis l'environnement utilisateur, plutôt qu'un Python intégré installé avec JMP 18 et les versions ultérieures. Dans JMP 14-17, la commande Python Send (dt) créait un dataframe Pandas dans l'environnement Python en enregistrant la table de données dans un fichier CSV temporaire, puis en forçant Pandas à lire ce fichier CSV dans un dataframe. Python Get(df) se comportait de manière analogue : Pandas écrivait le dataframe dans un fichier CSV et JMP importait ce fichier CSV. Cela signifiait que vous disposiez de deux copies des données : la table de données JMP et le dataframe Pandas.
Cela a changé dans JMP 18 avec l'introduction de Python 3.11.x intégré et d'un saut intégré Package d'importation fournissant une classe jmp.DataTable. Ceci introduit une référence dynamique en mémoire à la table de données JMP, accessible depuis Python. Python Send(dt); dans JMP 18+ crée désormais un objet jmp.DataTable au lieu d'un datagramme Pandas. dt2 = Python Get(dt) récupère simplement la référence de la table de données affectée à la variable. dfdt = Python Get(data_frame); utilise toujours l'ancien mécanisme pour convertir et charger la trame de données en table de données via un fichier CSV. Dans JMP 18, un exemple de script Python, disponible dans le répertoire des scripts, montre comment effectuer les conversions dt->csv->df et df->csv->dt originales. JMP 19 prend en charge le protocole Portable Dataframe ; il suffit donc d'une seule ligne pour convertir dt->df ou df->dt en mémoire. Exemples : dt2pandas.jsl, dt2pands.py, dt2pandas2dt.py
Pour JMP 17 :
Names Default to here(1);
dt = Open("$SAMPLE_DATA/Big Class.jmp");
// I have multiple Python's on system so I choose 3.10 where I have
// matplotlib, pandas, numpy, ... installed
Python Init(Use Python Version("3.10"));
Python Send(dt);
close(dt);
dtdf = Python Get("dt");
Show(dtdf);
dtdf << New Data View;
Cela fonctionne correctement sur ma machine. Si vous ne parvenez pas à l'exécuter, consultez votre journal pour voir si des erreurs s'affichent. Modifiez Python Init() pour votre environnement si nécessaire.
JMP 19
conn = Python Connect();
conn << Get Version();
conn << Execute( {},{},"\[
import jmp
import pandas as pd
import numpy as np
pandas_df = pd.DataFrame(
{
"A": 1.0,
"B": pd.Timestamp("20130102"),
"C": pd.Series(1, index=list(range(4)), dtype="float32"),
"D": np.array([3] * 4, dtype="int32"),
"E": pd.Categorical(["test", "train", "test", "train"]),
"F": "foo",
}
)
print( pandas_df )
# JMP 19 create a data table direcly from a dataframe
dt = jmp.from_dataframe(pandas_df)
print( dt )
]\", echo(1) );
show(dt);
// dt << New Data View; // already on screen
On peut faire beaucoup plus en exécutant simplement le script Python depuis l'éditeur, aucun wrapper JSL n'est nécessaire dans JMP 18+