取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 
The Discovery Summit 2025 Call for Content is open! Submit an abstract today to present at our premier analytics conference.
Get the free JMP Student Edition for qualified students and instructors at degree granting institutions.
选择语言 隐藏翻译栏
查看原发布的话题

使用 JMP 18、Python 和 SASPy 访问 SAS

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 和从 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 中。


使用 Python 连接到 SAS

要进行连接,您需要了解有关 SAS 实例的一些信息。即您将使用哪种类型的连接(Viya 还是 IOM)、SAS 服务器的位置以及访问它所需的任何凭据。

SASPy 具有高度可配置性,因此请参阅SASPy 文档以了解您的特定连接方案。我们介绍使用两种方法进行连接:

  • Viya,使用 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,这在用作数据管道的一部分进行转换、清理、创建数据等时非常有用。JMP 本身也能够将 pandas DataFrames 导入为 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)




如果成功,您应该会看到打开的 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 图表。鸣谢: @布莱恩·布恩@ChrisHemedinger


展望JMP 19

JMP 19 将继续支持 JMP 18 中使用 SASpy 的脚本、插件和管道,这意味着您在使用 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 文档

这篇帖子最初是用 English (US) 书写的,已做计算机翻译处理。当您回复时,文字也会被翻译成 English (US)。