Ciao a tutti,
Ho uno script JSL che crea un DataTable e ho un blocco di codice python all'interno dello script JSL che voglio passare al DataTable per fare previsioni sul DataTable usando un modello di apprendimento automatico addestrato. Prima del blocco di codice python, il DataTable è accessibile e si apre persino in JMP. Tuttavia, dopo il blocco di codice python quando provo ad accedere alle previsioni fatte dal modello di rete neurale basato sul DataTable usando "Show(preds_df)", ottengo l'errore "Nome non risolto: preds_df in accesso o valutazione di 'preds_df'". Sto usando JMP Pro 17. Di seguito è riportato il mio blocco di codice per la revisione.
<
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)
>
A ben vedere, preds_df è solo un dataframe pandas, non una tabella JMP, quindi non è possibile accedervi da JMP.
Prova questo alla fine del tuo script JSL:
dt = Python Get( preds_df );
dt << New Data View;
Inoltre JMP 18 può eseguire script Python in modo nativo, quindi non è necessario incorporarli negli script JSL.
Ho ricevuto "Invia si aspetta un oggetto scriptabile nell'accesso o nella valutazione di Invia, "dt" << /*###*/Nuova visualizzazione dati/*###*/ "
Puoi. Non ricordo se JMP17 è in grado di farlo direttamente, ma puoi ad esempio passare attraverso un file .csv: creare .csv dal dataframe pandas e quindi passare quel percorso a JMP e aprirlo.
Innanzitutto la sintassi per << Execute ( ) è errata. Vedere l'esempio nell'indice di scripting. Il primo parametro per Execute è un elenco JSL di input, seguito da un elenco JSL di variabili di output, seguito dallo script e quindi dal parametro facoltativo echo(1 o 0).
Lo script dovrebbe essere delineato dai marcatori di stringa "raw" di JSL "\[ script here ]\" per garantire che gli spazi vuoti e le terminazioni di riga siano preservati. Sono sorpreso che tu non stia ricevendo un errore di sintassi, ma vedo la stessa mancanza di errore su 19... Sto esaminando la questione. Lo spettacolo preds_df per me ha semplicemente stampato
dt = .;
che manca. Questo allora ovviamente significa:
dt << Nuova visualizzazione dati
Genera un errore perché dt (mancante) non è programmabile.
Il codice seguente riproduce il tuo problema.
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;
Questo codice funziona come previsto
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;
Un paio di cose degne di nota JMP 17 è l'ultima versione che ha utilizzato Python dall'ambiente dell'utente, anziché un Python incorporato installato con JMP 18 e versioni successive. In JMP 14-17 Python Send (dt); ha creato un dataframe pandas nell'ambiente Python salvando la tabella dati in un file CSV temporaneo, quindi facendo in modo che pandas leggesse quel file CSV in un dataframe. Python Get( df ); si è comportato in modo analogo, facendo in modo che pandas scrivesse il dataframe in un file CSV e che JMP importasse il file CSV. Ciò significava che avevi 2 copie dei dati, la tabella dati JMP e il dataframe pandas.
Ciò è cambiato in JMP 18 con l'introduzione di Python 3.11.x incorporato e di un gimp incorporato pacchetto di importazione che fornisce una classe jmp.DataTable. Ciò introduce un riferimento live in memoria alla tabella dati JMP accessibile da Python. Python Send( dt ); in JMP 18+ crea ora un oggetto jmp.DataTable invece di un datagramma pandas. dt2 = Python Get( dt ) ottiene solo il riferimento alla tabella dati che assegna alla variabile. dfdt = Python Get( data_frame ); utilizza ancora il vecchio meccanismo per convertire e caricare il dataframe come tabella dati tramite file CSV. In JMP 18 c'è uno script di esempio Python nella directory degli script che mostra come eseguire le conversioni originali dt->csv->df e df->csv->dt. JMP 19 supporta il Portable Dataframe Protocol, quindi è un one-liner per andare dt->df o df->dt in memoria. Esempi denominati dt2pandas.jsl, dt2pands.py, dt2pandas2dt.py
Per 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;
Funziona bene sulla mia macchina. Se non riesci a farlo funzionare, esamina il tuo Log per vedere se stai mostrando errori. Modificando Python Init() per il tuo ambiente, se necessario.
19 anni
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
Si può fare molto di più semplicemente eseguendo lo script Python dall'editor, senza bisogno di wrapper JSL in JMP 18+