Hola a todos,
Tengo un script JSL que crea una DataTable y un bloque de código Python dentro del script JSL que quiero pasar a la DataTable para realizar predicciones sobre ella usando un modelo de aprendizaje automático entrenado. Antes del bloque de código Python, la DataTable es accesible e incluso se abre en JMP. Sin embargo, después del bloque de código Python, cuando intento acceder a las predicciones realizadas por el modelo de red neuronal basado en la DataTable usando "Show(preds_df)", obtengo el error "Nombre sin resolver: preds_df en el acceso o la evaluación de 'preds_df'". Estoy usando JMP Pro 17. A continuación se muestra mi bloque de código para su revisión.
<
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)
>
Mirando rápidamente, preds_df es solo un marco de datos de pandas, no una tabla JMP, por lo que no se puede acceder a él desde JMP.
Pruebe esto al final de su script JSL:
dt = Python Get( preds_df );
dt << New Data View;
JMP 18 también puede ejecutar scripts de Python de forma nativa, por lo que no es necesario incrustarlos en scripts JSL.
Puedes. No recuerdo si JMP17 puede hacerlo directamente, pero puedes, por ejemplo, usar un archivo .csv: crea un archivo .csv desde el dataframe de Pandas y luego pasa esa ruta a JMP para abrirlo.
Primero, la sintaxis de << Execute() es incorrecta. Consulte el ejemplo en el índice de scripts. El primer parámetro de Execute es una lista JSL de entradas, seguida de una lista JSL de variables de salida, seguida del script y, finalmente, el parámetro opcional echo(1 o 0).
El script debe estar delimitado por los marcadores de cadena "sin procesar" de JSL "\[ script aquí ]\" para garantizar que se conserven los espacios en blanco y los finales de línea. Me sorprende que no recibas un error de sintaxis, pero veo la misma ausencia de error en 19... Estoy investigando. En mi caso, el comando show preds_df simplemente imprimió
dt = .;
que falta. Esto, por supuesto, significa:
dt << Nueva vista de datos
Lanza un error porque dt (faltante) no se puede programar.
El código siguiente replica su 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;
Este código se ejecuta como se esperaba
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 par de aspectos a destacar: JMP 17 es la última versión que utilizaba Python del entorno del usuario, en lugar de Python integrado, instalado con JMP 18 y versiones posteriores. En JMP 14-17, la función Send (dt); de Python creaba un dataframe de pandas en el entorno de Python guardando la tabla de datos en un archivo CSV temporal y haciendo que Pandas leyera dicho archivo CSV en un dataframe. La función Get(df); de Python funcionaba de forma análoga, haciendo que Pandas escribiera el dataframe en un archivo CSV y que JMP importara dicho archivo. Esto significaba que se tenían dos copias de los datos: la tabla de datos de JMP y el dataframe de Pandas.
Esto cambió en JMP 18 con la introducción de Python 3.11.x integrado y un saltar incorporado. Paquete de importación que proporciona una clase jmp.DataTable. Esto introduce una referencia activa en memoria a la tabla de datos de JMP, accesible desde Python. Python Send(dt); en JMP 18+ crea un objeto jmp.DataTable en lugar de un datagrama de Pandas. dt2 = Python Get(dt) simplemente obtiene la referencia de la tabla de datos, asignándola a la variable. dfdt = Python Get(data_frame); aún utiliza el mecanismo anterior para convertir y cargar el dataframe como una tabla de datos mediante un archivo CSV. En JMP 18, hay un script de ejemplo de Python en el directorio scripts que muestra cómo realizar las conversiones originales de dt->csv->df y df->csv->dt. JMP 19 es compatible con el protocolo Portable Dataframe, por lo que es muy sencillo convertir dt->df o df->dt en memoria. Los ejemplos se llaman dt2pandas.jsl, dt2pands.py y dt2pandas2dt.py.
Para 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;
Esto funciona correctamente en mi equipo. Si no puede ejecutarlo, revise su registro para ver si muestra errores. Si es necesario, modifique Python Init() para su entorno.
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
Se puede hacer mucho más simplemente ejecutando el script de Python desde el editor, no se necesita ningún contenedor JSL en JMP 18+