大家好,
我有一个创建数据表的 JSL 脚本,并且我在 JSL 脚本中有一个 Python 代码块,我想将数据表传递给该脚本,以便使用经过训练的机器学习模型对数据表进行预测。在 Python 代码块之前,数据表是可访问的,甚至可以在 JMP 中打开。但是,在 Python 代码块之后,当我尝试使用“Show(preds_df)”访问基于数据表的神经网络模型所做的预测时,我收到错误“名称未解析:preds_df 在访问或评估‘preds_df’时”。我使用的是 JMP Pro 17。以下是我的代码块以供审查。
<
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)
>
很快发现,preds_df 只是一个 pandas 数据框,而不是 JMP 表,因此你无法从 JMP 访问它。
在 JSL 脚本末尾尝试以下操作:
dt = Python Get( preds_df );
dt << New Data View;
此外,JMP 18 可以本地运行 Python 脚本,因此无需将它们嵌入到 JSL 脚本中。
有没有办法将数据框转换为 JMP 数据表,以便在 python 块之外对其进行可视化。
我收到“Send 期望可编写脚本的对象在访问或评估 Send 时,“dt”<< /*###*/New Data View/*###*/”
可以。我不记得 JMP17 是否能够直接执行此操作,但例如,您可以通过 .csv 文件:从 pandas 数据框创建 .csv,然后将该路径传递给 JMP 并打开它。
首先,<< Execute ( ) 的语法是错误的。请参阅脚本索引中的示例。Execute 的第一个参数是 JSL 输入列表,后跟 JSL 输出变量列表,后跟脚本,然后是可选的 echo(1 或 0) 参数。
脚本应该由 JSL 的“原始”字符串标记“\[ script here ]\”来划定,以确保保留空格和行尾。我很惊讶你没有收到语法错误,但我在 19 上看到同样的错误缺失......我正在调查这一点。对我来说,show preds_df 只是打印
dt = .;
缺少了。这当然意味着:
dt << 新数据视图
由于 dt(missing)无法编写脚本,因此引发错误。
下面的代码复制了您的问题。
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;
此代码按预期运行
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;
需要注意的几点是,JMP 17 是最后一个使用用户环境中的 Python 的版本,而不是 JMP 18 及更新版本中安装的嵌入式 Python。在 JMP 14-17 中,Python Send (dt);通过将数据表保存到临时 CSV 文件,然后让 pandas 将该 CSV 文件读入数据框,在 Python 环境中创建了 pandas 数据框。Python Get(df); 的行为类似,让 pandas 将数据框写入 CSV 文件,并让 JMP 导入该 CSV 文件。这意味着您有 2 份数据副本:JMP 数据表和 pandas 数据框。
随着嵌入式 Python 3.11.x 和内置跳转的引入,这种情况在 JMP 18 中发生了变化 导入包提供 jmp.DataTable 类。这引入了对可从 Python 访问的 JMP 数据表的内存实时引用。JMP 18+ 中的 Python Send(dt); 现在创建一个 jmp.DataTable 对象,而不是 pandas 数据报。dt2 = Python Get(dt) 仅获取分配给变量的数据表引用。dfdt = Python Get(data_frame); 仍然使用旧机制通过 CSV 文件将数据框转换为数据表并加载。在 JMP 18 中,脚本目录中有一个 Python 示例脚本,显示了如何执行原始 dt->csv->df 和 df->csv->dt 转换。JMP 19 支持可移植数据框协议,因此在内存中只需一行即可转到 dt->df 或 df->dt。示例名为 dt2pandas.jsl、dt2pands.py、dt2pandas2dt.py
对于 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;
这在我的计算机上运行良好。如果您无法运行它,请检查您的日志以查看是否显示错误。如有必要,请根据您的环境修改 Python Init()。
JMP19
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
只需从编辑器运行 Python 脚本即可完成更多操作,JMP 18+ 中无需 JSL 包装器