JMP 18은 Python 통합에 강력하고 새로운 기능을 제공합니다. 내장된 Python 3.11 버전, 패키지 설치 지원, 순수 Python 스크립트를 실행할 수 있는 Python 인식 스크립트 편집기, JMP 기능에 대한 Python 액세스를 제공하는 가져오기 jmp 패키지, 향상된 오류 보고 및 스크립팅 인덱스 지원을 포함하여 다음의 새로운 기능에 대한 예를 문서화하고 제공합니다. '파이썬' 카테고리.

여기서 초점은 특히 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를 호출하여 디스크에서 DataFrame으로 CSV 파일을 읽는 것이었습니다. 이는 작은 파일에는 적합하지만 큰 데이터에는 적합하지 않습니다. 첫째, 데이터 전송을 위해 파일 시스템을 사용해야 한다는 문제이다. 둘째, 바이너리에서 텍스트로 갔다가 다시 바이너리로 전환하면 정밀도가 손실될 가능성이 있습니다. 다음으로, CSV 파일은 일반적으로 원본 바이너리 데이터보다 훨씬 더 큽니다. 마지막으로 원본 테이블을 조작할 수 있는 방법이 아닌 Python에 데이터 복사본이 있습니다. Python Get( df )을 사용하여 Python 처리된 데이터를 JMP로 다시 가져옵니다. 정확히 동일한 과정을 반대로 수행합니다. 파이썬 Get(df); 호환성 문제로 인해 그대로 두었습니다.
18의 새로운 기능, Python Get( dt ); 실제 테이블의 JSL에 대한 데이터 테이블 참조를 검색합니다. 이는 제로 복사 작업입니다. 필요에 따라 Python Send( dt ); 더 이상 pandas.DataFrame을 생성하지 않습니다. Python에서는 jmp.DataTable 객체 에 대한 실시간 참조를 얻습니다. JMP 데이터 테이블. 이 역시 제로 복사 작업입니다. 이를 통해 Python에서 직접 액세스하여 JMP 데이터 테이블에 액세스하고, 편집하고, 수정할 수 있습니다. 새로운 JMP 테이블을 생성하는 과정에서 Python에서 jmp.DataTable 객체를 생성할 수 있습니다.
다음은 JMP 18.0 기능을 활용하여 JMP 데이터 테이블을 가져와 Python에서 두 열의 비율인 열을 추가하는 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]
]\");

결과적으로 로그 출력은 다음과 같습니다.
/*:
빅 클래스 증가: 40 ncols: 5 이름 나이 성별 키 몸무게 KATIE 0
이제 Python에서 직접 작업하는 방법을 살펴보겠습니다. 다음은 'Big Class.jmp'를 열고, jmp.DataTable 개체에서 메모리 내 팬더 데이터 프레임을 생성하고, '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 19는 Portable Dataframe Protocol을 지원하여, 한 줄의 코드로 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의 스크립팅 인덱스를 참조하여 예를 들어보세요.
최근 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에서 사용하는 데이터프레임 교환 프로토콜(DIP)이 pandas 3.0에서 더 이상 사용되지 않는 것으로 나타났습니다.
저는 JMP 파이썬 인스턴스에 pandas 3.0.2를 설치했었습니다. pandas를 2.2.3으로 롤백했더니 로그에 있던 메시지가 사라지고 중간 CSV 파일이 생성되지 않고 JMP 데이터 테이블이 생성되었습니다.
Pandas 3.0 버전에서 몇 가지 문제가 발생했습니다. Pandas의 문자열 열 처리 방식이 2.x에서 3.x로 변경되면서 문자열 열 처리 과정에서 오류가 발생했고, 이로 인해 Pandas 3.0.x 및 JMP 19.x 버전에서는 CSV 형식으로 대체 처리가 되었습니다. JMP 20에서는 이 문제를 해결했으며, 19.2 릴리스에 포함시킬 수 있는지 검토 중입니다. 상당한 양의 코드를 수정해야 했습니다.