JMP 18 とその組み込み Python 機能により、多くのオープンソース ツールにアクセスできるようになりました。これにより、SAS を含む多数のデータ ソースとのやり取りが可能になります。オープンソースの Python パッケージ SASPy を JMP 環境でどのように活用できるかを見てみましょう。このチュートリアルでは、次のことを行います。
- SASPy をインストールします。
- Python スクリプトを使用して SAS に接続します。
- SAS からデータ セットをダウンロードして開きます。
- テーブルを SAS にアップロードします。
- SAS コードを実行します。
要点だけに興味がある場合は、完全なサンプル スクリプトについては添付ファイルを参照してください。ただし、JMP での Python の使用法を復習したい場合は、次のブログ投稿が役立ちます。
JMP® 18 での Python 統合の開始
Pythonで実装されたJSL関数の作成
SASPy: JMP と SAS の接続
SAS が管理するオープンソースのSASPyを使用すると、Python を使用して SAS とインターフェイスできます。SASPy は、SAS Viya 接続、および統合オブジェクト モデル (IOM) を使用したローカル接続とリモート接続をサポートしています。接続後、堅牢な API を使用して SAS ライブラリのリストにアクセスしたり、ライブラリ情報、リスト テーブル、テーブル情報を取得したり、個々の列情報を取得したり、テーブルをダウンロードしたり、 pandas DataFramesとの間で変換したり、SAS コードを実行したり、SAS ログにアクセスしたり、SAS の統計および機械学習手順を利用したりすることができます。今のところはこれで十分でしょう。
JSL を使用した SASPy のインストール
JSL の世界から始めましょう。チュートリアルでは、numpy、pandas、SASPy が必要です。次の JSL スクリプトを実行して、必要なパッケージをインストールします。
Names Default To Here( 1 );
// install numpy and pandas packages
Python Install Packages( "numpy pandas saspy" );
ログを見て、パッケージが正しくインストールされていることを確認します。インストールされたパッケージは再起動後も JMP に保持されるため、インストールは 1 回だけ行う必要があります (成功した場合)。
Pythonを使用してSASに接続する
接続するには、SAS インスタンスに関する情報をいくつか知っておく必要があります。具体的には、使用する接続の種類 (Viya と IOM)、SAS サーバーの場所、およびアクセスに必要な資格情報です。
SASPy は高度に構成可能なので、特定の接続シナリオについてはSASPy のドキュメントを参照してください。次の 2 つの方法を使用した接続について説明します。
- Viya はhttp を使用して Viya インスタンスに接続します。Java のインストールは必要ありません。SAS 9.4 では動作しません。
- IOM では、マシンに Java がインストールされている必要があります。Windows 上のローカル インスタンスまたは任意のプラットフォーム上のリモート インスタンスにアクセスできます。
辞書を使って接続する
まず、JMP Python スクリプト ウィンドウを開きます。また、右クリックして [ログを開く] を選択して、埋め込みログを開きます。以下のスクリプトは、接続パラメータを含む Python ディクショナリを使用します。パラメータを SAS インスタンスに固有のものに置き換えると、接続できるようになります。SASSession の変数を接続タイプに対応するディクショナリに置き換え、右クリック メニューを使用して埋め込みログを開き、実行します。
セキュリティに関する注意:以下のテクニックは SAS 接続の検証/デバッグに役立ちますが、権限を厳密に制御できる別のファイルに資格情報を保存する方がおそらく良い選択肢です。組織のセキュリティ ポリシーが不明な場合は、システム管理者に問い合わせてサポートを受けてください。以下の手順で接続できる場合は、そのまま進んでください。ただし、その後、「構成ファイルを使用して接続する」セクションの手順に従って、資格情報をスクリプトから移動してください。
もう 1 つ注意点があります。JSLから Python を実行できますし、その逆も可能です。そのため、コードを実行するときは、隅に青と黄色の Python ロゴがあるかどうかを確認して、Python を実行するかどうかを判断するようにしてください。
最後にもう 1 つ注意点があります。JMPは実行中に Python スクリプトに制御を渡すため、コードの実行中は GUI が応答しないのが一般的です。
import saspy
viya = {
'url' : 'https://notrealsas.jmp.com:1234', # must contain http or https
'user': 'username',
'pw' : 'password',
'verify' : True, # verify certificates
}
iom = {
# location of java on your machine
'java': r'C:\Program Files (x86)\Common Files\Oracle\Java\javapath\javaw.exe',
}
iom_remote = {
'java': r'C:\Program Files (x86)\Common Files\Oracle\Java\javapath\javaw.exe',
'iomhost': 'notrealsas.jmp.com',
'iomport': 1234,
'omruser': 'username',
'omrpw': 'password',
}
# connect to SAS
# replace the second argument with your connection dict, mind the **
sas = saspy.SASsession(prompt=False, **viya)
print(sas)
接続が成功すると、埋め込みログに次のような内容が表示されます。
SAS Connection established. Subprocess id is 10040
Access Method = IOM
SAS Config name = default
SAS Config file = C:\Users\you\AppData\Roaming\JMP\JMP\Python\Python311\site-packages\saspy\sascfg.py
WORK Path = C:\Users\you\AppData\Local\Temp\SAS Temporary Files\_TD16996_SAS-PF4H167P_\Prc2\
SAS Version = 9.04.01M8P01182023
SASPy Version = 5.10.0
Teach me SAS = False
Batch = False
Results = Pandas
SAS Session Encoding = wlatin1
Python Encoding value = cp1252
SAS process Pid value = 16996
接続できない場合は、ログを注意深く読んで手がかりを探し、ユーザー名とパスワード(該当する場合)も確認してください。コードを実行する前に埋め込みログを開くと、print ステートメントと例外が表示されます。接続が失敗するその他の一般的な理由は次のとおりです。
- 経由
- SAS の URL アドレスにアクセスできないか、スペルが間違っています。
- 'url' パラメータをhttp(s)://としてフォーマットできません:たとえば、http : //server. jmp . com :5432
- SAS インスタンスが自己署名証明書を使用している場合は、「verify」フィールドを「true」としてマークします (警告: verify=false で接続すると、セキュリティ上のリスクが発生する可能性があります)。
- IOM
- Java がインストールされていない (Java をインストールした後、JMP またはコンピューターを再起動する必要がある場合があります)。
- Java 実行ファイルへのパスが正しくありません。JAVA_HOME の環境値を確認するか (Mac)、java フォルダーのパスを検索してください (Windows)。
設定ファイルを使用して接続する
次に、接続情報を別の場所に移動しましょう。繰り返しになりますが、システム管理者に連絡して、組織のセキュリティ プラクティスを遵守してください。この投稿に添付されているサンプル構成ファイル (sascfg_personal.py) をダウンロードし、値を自分の資格情報に置き換えます。このファイル内の SAS_config_names を書き留めて、接続オプションがそのリストに含まれていることを確認します。次に、ファイルの場所を使用して接続します。
import saspy
# replace with path to your config file
config_file = r'/some/path/to/your/config/sascfg_personal.py'
# replace the cfgname argument with the connection in your config file
sas = saspy.SASsession(prompt=False, cfgname='iom', cfgfile=config_file)
print(sas)
出力は、以前に接続したときと同じになるはずです。
データセットを開く
ファイルをダウンロードしてデータセットを開く
SAS データ セットをインポートする方法の 1 つは、ファイルを直接ダウンロードすることです。JMP はデータ セット ファイル タイプ (sas7bdat) をインポートできるため、データ形式とラベルを保持できます。以下に示す Python スクリプトは、SAS からファイルをダウンロードし、 Python スクリプト内でJSL を使用してファイルを開きます。
import saspy
import jmp
import tempfile
config_file = r"C:\Users\user\Documents\sascfg_personal.py"
sas = saspy.SASsession(prompt=False, cfgname='iom', cfgfile=config_file)
print("Connected to SAS", sas)
table_name = 'cars'
library_name = 'sashelp'
print('Download ' + library_name + '.' + table_name)
data = sas.sasdata(table_name, library_name)
metadata = data.contents()
remote_file = metadata['Enginehost'].query('Label1 == "Filename"')['cValue1'].item()
# save in temp
tmp_dir = tempfile.gettempdir()
print('Copying ' + remote_file + ' to ' + tmp_dir + '...')
sas.download(tmp_dir, remote_file)
print('Opening table...')
jmp.run_jsl('''
dt1 = Open(
"%s/cars.sas7bdat",
Use Labels for Var Names( 1 )
);
''' % (tmp_dir) )
Cars データ セットのデータを含むデータ テーブルが開きます。
pandas DataFrameを使用してデータセットを開く
SASpy を使用すると、データ セットを pandas DataFrame に変換したり、pandas DataFrame から変換したりできます。これは、変換、クリーニング、データの作成などを実行するデータ パイプラインの一部として使用すると便利です。JMP 自体も pandas DataFrame を JMP テーブルとしてインポートできるため、可能性がさらに広がります。
以下のPythonの例では、SASHELP.classデータセットをDataFrameとして開き、JMPテーブルを開き、定義されたユーティリティ関数dataFrameToJmpTable()を使用して、DataFrameの値をJMPテーブルに入力します。
import saspy
import jmp
config_file = r"C:\Users\user\Documents\sascfg_personal.py"
sas = saspy.SASsession(prompt=False, cfgname='iom', cfgfile=config_file)
def dataFrameToJmpTable(dataFrame, table):
# Populate a jmp data table with a pandas dataframe
# Credit: Paul Nelson
cols = dataFrame.columns
values = dataFrame.values
for (i,k) in enumerate(cols):
print(i, k, dataFrame[k].dtype)
l = values[:,i].tolist() # turn pandas (numpy) column to a list
# create new columns based on the data type of the pandas column
value = values[0,:][i] # get example value from the i'th column
print("Example value: ", value)
if dataFrame[k].dtype == object and isinstance(value, str):
table.new_column(k, jmp.DataType.Character)
table[k] = l
elif dataFrame[k].dtype == 'float64': # numpy.number:
table.new_column(k, jmp.DataType.Numeric)
table[k] = l
elif dataFrame[k].dtype == 'int64': # or 'int32'
table.new_column(k, jmp.DataType.Numeric, dlen=4)
table[k] = l
else:
print('Unhandled column type: {dataFrame[k].dtype} . Defaulting to string.')
table.new_column(k, jmp.DataType.Character)
table[k] = l
sasData = sas.sasdata('Class', 'SASHELP',
results='pandas',
# dsopts={'where':'Age > 12',}
)
dataFrame = sasData.to_df()
values = dataFrame.values
num_rows = len(values)
dt = jmp.DataTable(name='Class', rows=num_rows)
dataFrameToJmpTable(dataFrame, dt)
成功すると、開いたクラス データ テーブルが表示されます。
SAS へのファイルのアップロード
データ セットのダウンロードと同様に、SASPy が提供する DataFrame インターフェイスを使用して、データを SAS にアップロードしたり、JMP ファイルをアップロードしたりできます。以下は、JMP データ テーブル ファイルを SAS にアップロードし、SAS プロシージャ PROC IMPORT を使用してインポートする例です。
import saspy
import jmp
config_file = r"C:\Users\user\Documents\sascfg_personal.py"
sas = saspy.SASsession(prompt=False, cfgname='iom', cfgfile=config_file)
table_name = 'animals.jmp'
remote_file = sas.workpath + table_name
local_file = jmp.SAMPLE_DATA + table_name
results = sas.upload(local_file, remote_file, overwite=True)
print(results)
# import uploaded file as a data set, replace data set if existing
command = '''
PROC IMPORT OUT= WORK.animals
DATAFILE="{jmp_file}"
DBMS=JMP REPLACE;
RUN;
'''.format(jmp_file=remote_file)
results = sas.submit(command)
print(results)
埋め込まれたログを確認するか、ファイルをダウンロードして、動作したことを確認します。
以下は、DataFrames を使用したアップロード戦略です。まず、JMP テーブルを DataFrame に変換し、次に dataframe2sasdata() を使用してアップロードします。
import saspy
import numpy as np
import pandas as pd
config_file = r"C:\Users\user\Documents\sascfg_personal.py"
sas = saspy.SASsession(prompt=False, cfgname='iom', cfgfile=config_file)
def jmpTableToDataFrame(dt) :
# Credit to Paul Nelson again
# Creating a Pandas dataframe from a JMP DataTable
df = pd.DataFrame()
for idx in range( len(dt) ):
if dt[idx].dtype == jmp.DataType.Numeric:
# creates numeric column directly using Python's Buffer Protocol
col = np.array( dt[idx] )
df[ dt[idx].name ] = col.tolist() # make it a list for pandas.
elif dt[idx].dtype == jmp.DataType.Character:
# create a list by iterating through values
col = list()
for i in range ( dt.nrows ):
col.append(dt[idx][i])
# Build character column from list
df[ dt[idx].name ] = col
else:
print("Not adding type:", dt[idx].dtype )
return df
data_table = jmp.open(jmp.SAMPLE_DATA + "Fitness.jmp")
df = jmpTableToDataFrame(data_table)
result = sas.dataframe2sasdata(df, 'Fitness', 'WORK')
print('WORK Tables:', sas.list_tables('WORK'))
埋め込まれたログをチェックして、Fitness テーブルが WORK テーブルのリストに表示されるかどうかを確認します。
私の経験では、アップロード/ダウンロード戦略にファイル全体を使用する方が、2 つの戦略のうち高速になる傾向があります。また、データ変換や表現の問題も制限されます。一方、DataFrames は他の Python モジュールで広く受け入れられています。データに対して追加の Python 作業を行う必要がない限り、ファイル戦略を使用することをお勧めします。
SAS コードの実行
前のセクションでは、 sas.submit() 関数を使用して SAS コードを実行し、ファイルをインポートしましたが、これはどの SAS コードでも実行できます。添付の saspy_cowboy_hat.jsl で、JSL スクリプト内で SASPy を使用し、SAS コードを実行してクラシック SAS グラフを作成して表示する例を確認してください。提供元: ブライアン・ブーンおよび@クリス・ヘメディンガー 。
JMP 19に向けて
JMP 18 で SASpy を使用したスクリプト、アドイン、パイプラインは JMP 19 でも引き続きサポートされます。つまり、SAS を使用する際に、作成されたインフラストラクチャを引き続き使用して構築することができます。さらに、JMP 19 では、SAS 統合に関連する多くの機能が提供され、この記事で説明したスクリプトやテクニックがさらに強化されます。SAS エクスポート ダイアログやさまざまな JSL SAS 統合関数など、使い慣れた機能も復活します。これらはすべてデータ コネクタ インフラストラクチャ上に構築されており、組織全体で SAS 接続を簡単に構成、共有、および利用できるようにします。
現在 JMP 18 をお持ちで、JMP 19 が製品化される前に将来の SAS 統合機能を試してみませんか? 集中的なフィードバックと指示を提供するには、JMP 19 アーリー アダプター (EA) プログラムに申し込むのが最適です。詳細については、 jmp.com/アーリーアダプターにアクセスしてください。
Python が提供する堅牢なオープンソース ツールを JMP に組み込むことで、データにアクセスして操作する機会が数多く得られます。完全な SASPy デモ スクリプトは、この投稿に添付されています。
また、SASPy をサポートしていただいた Tom Weber 氏にも心から感謝いたします。オープンソース パッケージとして、 SASPy への改善や提案を github に投稿することを検討してください。
みなさん、スクリプト作成を楽しんでください!
リソース
SASPy 構成
SASPy Python API
SASPy サンプル Jupiter ノートブック
pandas ドキュメント