JMP 18 及其嵌入式 Python 功能提供了對許多開源工具的訪問,從而為與包括 SAS 在內的許多資料來源互動打開了大門!讓我們來探索如何在 JMP 環境中利用開源 Python 套件 SASPy。在本教程中,我們:
- 安裝 SASPy。
- 使用 Python 腳本連接到 SAS。
- 從 SAS 下載並開啟資料集。
- 將表上傳至 SAS。
- 執行 SAS 程式碼。
如果您只對妙語感興趣,請參閱附件中的完整範例腳本。但如果您想重新了解如何使用 Python 和 JMP,以下部落格文章可以為您提供幫助:
JMP® 18 中 Python 的整合入門
建立用 Python 實作的 JSL 函數
SASPy:將 JMP 與 SAS 連接起來
由 SAS 維護的開源沙門氏菌可讓您使用 Python 與 SAS 互動。 SASPy 支援 SAS Viya 連接,以及使用整合物件模型 (IOM) 的本地和遠端連接。連接後,可以使用強大的 API 存取 SAS 庫列表;取得庫資訊、列出表、表格資訊;取得單獨列的資訊;下載表格;與pandas DataFrames 相互轉換;運行 SAS 程式碼;存取 SAS 日誌;利用 SAS 統計和機器學習程式;而且...也許現在就夠了。
使用 JSL 安裝 SASPy
讓我們從 JSL-land 開始。對於本教程,我們需要 numpy、pandas 和 SASPy。執行以下 JSL 腳本來安裝所需的套件。
Names Default To Here( 1 );
// install numpy and pandas packages
Python Install Packages( "numpy pandas saspy" );
透過查看日誌驗證軟體包是否正確安裝。您只需安裝一次(假設安裝成功),因為已安裝的套件在重新啟動後仍會保留在 JMP 中。
使用 Python 連接到 SAS
要連接,您需要了解有關 SAS 實例的一些資訊。即您將使用哪種類型的連接(Viya 與 IOM)、SAS 伺服器的位置以及存取它所需的任何憑證。
SASPy 具有高度可設定性,因此請參閱SASPy 文件以了解您的特定連接場景。我們介紹使用兩種方法進行連接:
- 透過使用 http 連線到 Viya 實例,無需安裝 Java。不適用於 SAS 9.4。
- IOM,要求您的機器上安裝 Java。可以存取 Windows 上的本機執行個體或任何平台上的遠端執行個體。
使用字典進行連接
首先開啟 JMP Python 腳本視窗。也可以透過右鍵單擊並選擇“開啟日誌”來開啟嵌入的日誌。下面的腳本使用包含連接參數的 Python 字典。將參數替換為特定於您的 SAS 實例的參數將允許您進行連線。用與您的連線類型相對應的字典取代 SASSession 中的變量,使用右鍵選單開啟嵌入日誌,然後執行它。
安全注意事項:雖然以下技術可以幫助驗證/調試您的 SAS 連接,但將您的憑證保存在可以嚴格控制權限的單獨文件中可能是更好的選擇。如果您不確定組織的安全政策,請與系統管理員聯絡以尋求支援。如果以下步驟允許您連接,請繼續歡呼,但請使用「使用設定檔連接」部分中的步驟將您的憑證移出腳本。
另一個注意事項:我們可以從 JSL 執行 Python,反之亦然,因此在運行程式碼時,請務必檢查角落是否有藍色和黃色的 Python 標誌,以確定您是否即將運行 Python。
最後一點說明: 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
如果無法連接,請仔細閱讀日誌尋找線索,並驗證您的使用者名稱和密碼(如果適用)。在運行程式碼之前打開嵌入日誌將顯示列印語句以及任何異常。連線失敗的其他常見原因包括:
- 透過
- SAS 的 URL 位址無法存取或拼字錯誤。
- 未能將「url」參數格式化為http(s):// :例如,http : //server.jmp . com :5432
- 當 SAS 實例使用自簽名憑證時,將「驗證」欄位標記為「true」(警告:使用 verify=false 進行連線可能存在安全風險)。
- 國際移民組織
- 未安裝 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 資料集的一種方法是直接下載檔案。 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) )
您應該會看到一個開啟的資料表,其中包含來自汽車資料集的資料。
使用 pandas DataFrame 開啟資料集
SASpy 允許將資料集轉換為 pandas DataFrame 或從 pandas DataFrame 轉換為 pandas DataFrame,這在用作資料管道的一部分進行轉換、清理、建立資料等時非常有用。
在下面的 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)
如果成功,您應該會看到開啟的 Class 資料表。
將檔案上傳至 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 表列表中。
根據我的經驗,使用整個文件進行上傳/下載策略往往是兩種策略中更快的。它還限制資料轉換或表示問題。另一方面,DataFrames 被其他 Python 模組廣泛接受。我建議使用檔案策略,除非您需要對資料進行額外的 Python 工作。
執行 SAS 程式碼
在上一節中,我們使用了 sas.submit() 函數來執行 SAS 程式碼來匯入文件,但我們可以使用任何 SAS 程式碼來執行此操作。請參閱附件 saspy_cowboy_hat.jsl 的範例,該範例示範如何在 JSL 腳本中使用 SASPy 並執行 SAS 程式碼來建立和查看經典 SAS 圖。來源: @bryan_boone和@ChrisHemedinger 。
展望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/earlyadopter 。
透過將 Python 提供的強大開源工具整合到 JMP 中,存取和互動資料的機會變得非常多。完整的 SASPy 演示腳本可在本帖附件中找到。
另外,非常感謝 Tom Weber 對 SASPy 的支持。作為一個開源包,請考慮 在 github 上向 SASPy貢獻改進或建議。
祝大家寫腳本愉快!
資源
SASPy 配置
SASPy Python API
SASPy 範例 Jupiter 筆記本
pandas 文檔