JMP 18 Python jmp.DataTable と pandas.DataFrameJMP 18 は、Python 統合に強力な新機能をもたらします。Python 3.11 の組み込みバージョン、パッケージ インストール サポート、純粋な Python スクリプトを実行できる Python 対応スクリプト エディター、JMP 機能への Python アクセスを提供するインポート jmpパッケージ、強化されたエラー レポート、および「Python」カテゴリで新機能の例を文書化して提供するスクリプト インデックス サポートが含まれます。

ここでの焦点は、特に jmp.DataTable オブジェクトと、 Python Send(dt)およびPython Get(df)に関して JMP 18 が行った変更です。ここで、「dt」はデータ テーブル、「df」は pandas.DataFrame です。
JMP 14-17 では、JSL コマンドPython Send( dt );を使用して、JMP データ テーブルのコピーを Python 環境に転送する機能が提供されました。この機能は、JMP がファイル システム内の一時 CSV ファイルにデータ テーブルを書き込み、次に pandas を呼び出して CSV ファイルをディスクから DataFrame に読み込むという仕組みで実行されていました。これは、小さなファイルには問題なく機能しますが、大きなデータには適していません。まず、データ転送にファイル システムを使用する必要があるという問題があります。次に、バイナリからテキストに変換してから再びバイナリに戻すと、精度が失われる可能性があります。次に、CSV ファイルは通常、元のバイナリ データよりも大幅に大きくなります。最後に、Python にはデータのコピーがあり、元のテーブルを操作する方法はありません。Python で処理されたデータをPython Get ( df ); を使用して JMP に戻すと、まったく同じプロセスが逆方向に実行されます。Python Get( df ); は、互換性の理由からそのまま残されています。
18の新機能、 Python Get ( dt );は、実際のテーブルのJSLへのデータテーブル参照を取得します。これはゼロコピー操作です。必然的に、 Python Send( dt );はpandas.DataFrameを作成しなくなりました。Pythonでは、jmp.DataTableオブジェクトを取得します。これは、 JMP データ テーブル。これもゼロ コピー操作です。これにより、Python から直接アクセスして、JMP データ テーブルにアクセスし、編集および変更できます。Python から jmp.DataTable オブジェクトを作成し、その過程で新しい JMP テーブルを作成できます。
以下は、JMP 18.0 の機能を利用して JMP データ テーブルを取得し、Python から 2 つの列の比率である列を追加する JSL スクリプトです。これを現在のデータ テーブルでライブで実行します。
// 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]
]\");

ログ出力は次のようになります:
/*:
ビッグクラス nrows: 40 ncols: 5 名前 年齢 性別 身長 体重 KATIE 0
それでは、Python から直接操作する方法を紹介します。以下は、'Big Class.jmp' を開き、jmp.DataTable オブジェクトからメモリ内に pandas データ フレームを作成し、'Big Class' を閉じ、DataFrame から新しい JMP データ テーブルを構築し、最後に JSL で現在のデータ テーブルの列名を出力する Python スクリプトです。現在のテーブルは、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 サポートを含む多くの新機能が搭載されています。その主な機能の 1 つは、Python から JMP データ テーブルに直接アクセス、変更、および作成できることです。これは、jmp.DataTable Python オブジェクトを通じて実現されます。この記事では、JMP データ テーブルから pandas.DataFrame を作成する方法と、その逆に、ライブおよびメモリ内の pandas.DataFrame から JMP データ テーブルを作成する方法を説明します。
自動化とスクリプトデータアクセスRe: JMP® 18 の新機能: Python jmp.DataTable と pandas.DataFrameこの機能は今年のユーザー カンファレンスでデモされたので、共有することができます。
JMP 19 では、Portable Dataframe Protocol がサポートされるようになりました。これにより、1 行のコードで 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 パッケージに、メモリ内のデータフレームから JMP データ テーブルを作成する from_dataframe( df ) メソッドが追加されました。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 のスクリプト インデックスを参照してください。
Re: JMP® 18 の新機能: Python の jmp.DataTable と pandas.DataFrame最近、JMP 19.1.1 をインストールし、 @Paul_Nelsonさんが上記で説明している jmp.from_dataframe() メソッドを、彼のサンプルコードを使って試してみました。すると、中間の一時的な 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インスタンスのPythonにはpandas 3.0.2がインストールされていました。pandas 2.2.3にロールバックしたところ、ログのメッセージが消え、中間CSVファイルが作成されることなくJMPデータテーブルが生成されました。
Re: JMP® 18 の新機能: Python の jmp.DataTable と pandas.DataFramePandas 3.0 では、いくつかの問題が発生しました。Pandas 2.x から 3.x への変更に伴い、文字列列の処理方法が変更されました。これにより、文字列列の処理でエラーが発生し、結果として Pandas 3.0.x と JMP 19.x の組み合わせで CSV へのフォールバックが発生しました。この問題は JMP 20 で修正済みであり、19.2 リリースで修正が可能かどうかを検討中です。かなりの量のコード変更が必要となりました。