Hallo zusammen,
Ich verfüge über ein JSL-Skript, das eine DataTable erstellt, und einen Python-Codeblock innerhalb des JSL-Skripts, an den ich die DataTable übergeben möchte, um mithilfe eines trainierten Machine-Learning-Modells Vorhersagen für die DataTable zu treffen. Vor dem Python-Codeblock ist die DataTable zugänglich und kann sogar in JMP geöffnet werden. Nach dem Python-Codeblock erhalte ich jedoch die Fehlermeldung „Name nicht aufgelöst: preds_df beim Zugriff oder bei der Auswertung von ‚preds_df‘“. Ich verwende JMP Pro 17. Nachfolgend finden Sie meinen Codeblock zur Überprüfung.
<
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)
>
Versuchen Sie dies am Ende Ihres JSL-Skripts:
dt = Python Get( preds_df );
dt << New Data View;
Außerdem kann JMP 18 Python-Skripte nativ ausführen, sodass sie nicht in JSL-Skripte eingebettet werden müssen.
Gibt es eine Möglichkeit, den Datenrahmen in eine JMP-Datentabelle zu konvertieren, um ihn außerhalb des Python-Blocks zu visualisieren?
Das ist möglich. Ich weiß nicht mehr, ob JMP17 das direkt kann, aber Sie können beispielsweise eine CSV-Datei verwenden: Erstellen Sie eine CSV-Datei aus dem Pandas-Datenrahmen, übergeben Sie diesen Pfad an JMP und öffnen Sie sie.
Zunächst ist die Syntax für << Execute ( ) falsch. Siehe das Beispiel im Skriptindex. Der erste Parameter für Execute ist eine JSL-Liste von Eingaben, gefolgt von einer JSL-Liste von Ausgabevariablen, dem Skript und dem optionalen Parameter echo(1 oder 0).
Das Skript sollte durch die JSL-Zeichenfolgenmarkierungen „\[ script here ]\“ gekennzeichnet sein, um sicherzustellen, dass Leerzeichen und Zeilenenden erhalten bleiben. Ich bin überrascht, dass Sie keinen Syntaxfehler erhalten, aber ich sehe den gleichen Fehler bei 19 … Ich untersuche das. Bei mir wurde „show preds_df“ einfach ausgegeben.
dt = .;
was fehlt. Das bedeutet dann natürlich:
dt << Neue Datenansicht
Gibt einen Fehler aus, weil dt (missing) nicht skriptfähig ist.
Der folgende Code reproduziert Ihr Problem.
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;
Dieser Code wird wie erwartet ausgeführt
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;
Ein paar Anmerkungen: JMP 17 ist die letzte Version, die Python aus der Benutzerumgebung nutzte, anstatt des eingebetteten Pythons, das mit JMP 18 und neuer installiert wurde. In JMP 14-17 erstellte Python Send (dt); einen Pandas-Datenrahmen in der Python-Umgebung, indem die Datentabelle in einer temporären CSV-Datei gespeichert wurde. Pandas ließ diese CSV-Datei dann in einen Datenrahmen einlesen. Python Get(df); verhielt sich analog, indem Pandas den Datenrahmen in eine CSV-Datei schrieb und JMP die CSV-Datei importierte. Dies bedeutete, dass Sie zwei Kopien der Daten hatten: die JMP-Datentabelle und den Pandas-Datenrahmen.
Dies änderte sich in JMP 18 mit der Einführung des eingebetteten Python 3.11.x und eines eingebauten jmp Importpaket, das eine jmp.DataTable-Klasse bereitstellt. Dies führt eine Livereferenz im Arbeitsspeicher auf die von Python aus zugängliche JMP-Datentabelle ein. Python Send(dt); erstellt in JMP 18+ jetzt ein jmp.DataTable-Objekt anstelle eines Pandas-Datagramms. dt2 = Python Get(dt) ruft einfach die Datentabellenreferenz ab, die der Variable zugewiesen wird. dfdt = Python Get(data_frame); verwendet weiterhin den alten Mechanismus, um den Datenrahmen als Datentabelle über eine CSV-Datei zu konvertieren und zu laden. In JMP 18 gibt es im Skriptverzeichnis ein Python-Beispielskript, das zeigt, wie die ursprünglichen Konvertierungen dt->csv->df und df->csv->dt durchgeführt werden. JMP 19 unterstützt das Portable Dataframe Protocol, sodass die Konvertierung von dt->df oder df->dt im Speicher mit einem Einzeiler erledigt ist. Beispiele mit den Namen dt2pandas.jsl, dt2pands.py, dt2pandas2dt.py
Für 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;
Das funktioniert auf meinem Rechner einwandfrei. Falls es nicht funktioniert, überprüfen Sie bitte Ihr Protokoll auf Fehler. Passen Sie Python Init() gegebenenfalls an Ihre Umgebung an.
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
Es lässt sich noch viel mehr tun, indem man einfach das Python-Skript aus dem Editor ausführt. In JMP 18+ ist kein JSL-Wrapper erforderlich.