JMP 18 Python jmp.DataTable 和 pandas.DataFrameJMP 18 在 Python 集成方面带来了强大的新功能。包括 Python 3.11 的嵌入式版本、包安装支持、可以运行纯 Python 脚本的 Python 感知脚本编辑器、提供 Python 访问 JMP 功能的导入 jmp包、增强的错误报告和脚本索引支持,记录和提供“Python”类别下新功能的示例。

这里的重点是 jmp.DataTable 对象以及 JMP 18 对Python Send ( dt )和Python Get( df )所做的更改。其中 'dt' 是数据表,'df' 是 pandas.DataFrame。
JMP 14-17 提供了使用 JSL 命令Python Send( dt );将 JMP 数据表的副本传输到 Python 环境的功能。其后台运行的方式是,JMP 将数据表写入文件系统中的临时 CSV 文件,然后调用 pandas 将 CSV 文件从磁盘读入 DataFrame。这种方法对小文件有效,但不适合较大的数据。首先,存在必须使用文件系统进行数据传输的问题。其次,从二进制转换为文本再转换回二进制可能会丢失精度。接下来,CSV 文件通常比原始二进制数据大得多。最后,您拥有 Python 中的数据副本,而不是操作原始表的方法。使用Python Get( df );将 Python 处理的数据带回 JMP 中,过程与此相反。出于兼容性原因,Python Get( df );保持不变。
18 版中的新增功能Python Get(dt);检索实际表的 JSL 数据表引用。这是一个零拷贝操作。Python Send(dt);必然不再创建 pandas.DataFrame。在 Python 中,您将获得一个 jmp.DataTable 对象,它是对 JMP 数据表。这也是零复制操作。它允许从 Python 直接访问、编辑和修改 JMP 数据表。在创建新 JMP 表的过程中,您可以从 Python 创建 jmp.DataTable 对象。
下面是一个 JSL 脚本,利用 JMP 18.0 功能获取 JMP 数据表,添加一个表示两列之比的列,该列来自 Python。在当前数据表上实时执行此操作。
// BigClass_hw_ratio.jsl
// Description: Show JMP 18 Python integration features
//
Names Default to Here(1);
dt = Open("$SAMPLE_DATA/Big Class.jmp");
Python Send(dt);
Python Submit("\[
import jmp
# print some information on data table properites
print(dt.__class__)
print(dt.name)
print(f'nrows: {dt.nrows}')
print(f'ncols: {dt.ncols}')
# data table object columns may be indexed either by
# column name or index. Note: slice is only supported
# when using indexes. Slice on both columns and rows is supported.
for x in dt[0:]:
print( x.name )
# As is Python convention, indexing is 0-based
print( dt['name'][0] )
# create a new column based on data from the original data.
# Because JMP is column centric, the access to
# jmp.DataTable object is [column][row]
dt.new_column('H/W ratio', jmp.DataType.Numeric)
for idx in range(dt.nrows):
dt['H/W ratio'][idx] = dt['height'][idx] / dt['weight'][idx]
]\");

导致日志输出:
/*:
大类 行数: 40 列数: 5 姓名 年龄 性别 身高 体重 KATIE 0
现在让我们展示如何直接从 Python 工作。下面是一个 Python 脚本,它打开“Big Class.jmp”,从 jmp.DataTable 对象在内存中创建一个 pandas 数据框,关闭“Big Class”,然后从 DataFrame 构建一个新的 JMP 数据表,最后在 JSL 中打印当前数据表的列名。当前表是刚刚在 Python 中创建的表。

# dt2pandas2dt.py
# Description: Example showing creating a pandas.DataFrame from a .jmp file,
# then creating a new data table from the data frame.
# This process happening live and in-memory.
#
import jmp
import numpy as np
import pandas as pd
from pandas.api.types import is_object_dtype, is_numeric_dtype, is_bool_dtype, is_string_dtype
# creating a Pandas dataframe from a JMP DataTable directly
dt = jmp.open(jmp.SAMPLE_DATA + "Big Class.jmp")
# create pandas DataFrame from Big Class
df = pd.DataFrame()
for idx in range( len(dt) ):
df[ dt[idx].name ] = np.array( dt[idx] )
print(df)
# we can close dt since we no longer need it open, we
# have everyting in df
dt.close(save=False)
# create JMP DataTable from pandas DataFrame
dt2 = jmp.DataTable('BC2', df.shape[0])
# get the column names from the data frame
names = list(df.columns)
# loop across the columns of the data frame
for j in range( df.shape[1] ):
# check if the coulumn data type is string or numeric
if is_string_dtype(df[ names[j] ] ):
dt2.new_column(names[j], jmp.DataType.Character )
else:
dt2.new_column(names[j], jmp.DataType.Numeric )
# populate the JMP column with data
dt2[j] = list(df.iloc[:,j])
# Just as JSL has a Python Submit(); to execute Python code
# the jmp object has a run_jsl() command to execute JSL from Python
jmp.run_jsl('''
Names Default to Here(1);
Current Data Table() << Get Column Names;
''')
有日志输出
/*:
name age sex height weight
0 KATIE 12.0 F 59.0 95.0
1 LOUISE 12.0 F 61.0 123.0
2 JANE 12.0 F 55.0 74.0
3 JACLYN 12.0 F 66.0 145.0
4 LILLIE 12.0 F 52.0 64.0
5 TIM 12.0 M 60.0 84.0
6 JAMES 12.0 M 61.0 128.0
7 ROBERT 12.0 M 51.0 79.0
8 BARBARA 13.0 F 60.0 112.0
9 ALICE 13.0 F 61.0 107.0
10 SUSAN 13.0 F 56.0 67.0
11 JOHN 13.0 M 65.0 98.0
12 JOE 13.0 M 63.0 105.0
13 MICHAEL 13.0 M 58.0 95.0
14 DAVID 13.0 M 59.0 79.0
15 JUDY 14.0 F 61.0 81.0
16 ELIZABETH 14.0 F 62.0 91.0
17 LESLIE 14.0 F 65.0 142.0
18 CAROL 14.0 F 63.0 84.0
19 PATTY 14.0 F 62.0 85.0
20 FREDERICK 14.0 M 63.0 93.0
21 ALFRED 14.0 M 64.0 99.0
22 HENRY 14.0 M 65.0 119.0
23 LEWIS 14.0 M 64.0 92.0
24 EDWARD 14.0 M 68.0 112.0
25 CHRIS 14.0 M 64.0 99.0
26 JEFFREY 14.0 M 69.0 113.0
27 MARY 15.0 F 62.0 92.0
28 AMY 15.0 F 64.0 112.0
29 ROBERT 15.0 M 67.0 128.0
30 WILLIAM 15.0 M 65.0 111.0
31 CLAY 15.0 M 66.0 105.0
32 MARK 15.0 M 62.0 104.0
33 DANNY 15.0 M 66.0 106.0
34 MARTHA 16.0 F 65.0 112.0
35 MARION 16.0 F 60.0 115.0
36 PHILLIP 16.0 M 68.0 128.0
37 LINDA 17.0 F 62.0 116.0
38 KIRK 17.0 M 68.0 134.0
39 LAWRENCE 17.0 M 70.0 172.0
//:*/
Names Default to Here(1);
Current Data Table() << Get Column Names;
/*:
{name, age, sex, height, weight}
在未来的博客文章中将会有更多的示例。
JMP 18 带来了许多新功能,包括改进的 Python 支持。其中一个主要功能是直接从 Python 访问、修改和创建 JMP 数据表。这是通过 jmp.DataTable Python 对象实现的。这篇文章将展示如何从 JMP 数据表创建 pandas.DataFrame,反之亦然,从 pandas.DataFrame 实时和内存中创建 JMP 数据表。
自动化和脚本数据访问回复:JMP® 18 中的新功能:Python jmp.DataTable 和 pandas.DataFrame现在,此功能已在今年的用户大会上进行了演示,我可以与大家分享。
JMP 19 提供了对可移植数据框协议的支持,让我们能够通过一行代码来转换 pandas 或任何其他兼容的数据框。获取后,请参阅 19 EA 或 19 中的脚本索引。
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)
dt = jmp.from_dataframe(pandas_df)
print(dt)
jmp 包现在有一个 from_dataframe( df ) 方法,该方法将从内存中的数据框创建 JMP 数据表。Pandas 还支持 Portable Data Frame 协议。由于我们实现了接口,因此 pandas 可以直接从 jmp.DataTable 对象创建数据框。
import jmp
import pandas as pd
dt = jmp.open(jmp.SAMPLE_DATA + "Big Class.jmp")
pandas_df = (pd.api.interchange.from_dataframe(dt))
print(pandas_df)
其他支持数据帧协议的软件包包括 Polars 和 Ibis。再次参见 19 中的脚本索引以获取示例。
回复:JMP® 18 新增功能:Python jmp.DataTable 和 pandas.DataFrame我最近安装了 JMP 19.1.1,并尝试了@Paul_Nelson上面描述的方法,使用了他提供的示例代码。我发现它仍然使用了中间的临时 CSV 文件,并且在日志中出现了以下消息:
:16: Pandas4Warning: The Dataframe Interchange Protocol is deprecated.
For dataframe-agnostic code, you may want to look into:
- Arrow PyCapsule Interface: https://arrow.apache.org/docs/format/CDataInterface/PyCapsuleInterface.html
- Narwhals: https://github.com/narwhals-dev/narwhals
ValueError: ArrowCTypes for string columns must be UTF-8 Strings or UTF-8 Large Strings.
The above exception was the direct cause of the following exception:
SystemError:
returned a result with an exception set
进一步调查显示, JMP 使用的数据帧交换协议似乎在 pandas 3.0 中已被弃用。
我的 JMP 实例中安装了 pandas 3.0.2。我回滚到 pandas 2.2.3 后,日志中的消息消失了,JMP 数据表也生成了,而没有生成中间 CSV 文件。
回复:JMP® 18 新增功能:Python jmp.DataTable 和 pandas.DataFramePandas 3.0 带来了一些问题。Pandas 3.0 对字符串列的处理方式从 2.x 版本升级到了 3.x 版本。这导致我们在处理字符串列时出现错误,进而导致在使用 Pandas 3.0.x 和 JMP 19.x 时回退到 CSV 格式。我们已经在 JMP 20 中修复了这个问题,目前正在研究是否可以在 19.2 版本中发布。为此,我们不得不修改大量代码。