大家好。感谢各位今天莅临。今天我将就我参与的一个项目进行演讲,演讲题目是《从开发到测试:JMP插件的创建与验证之旅》。
简单介绍一下我自己。我目前是美国克莱姆森大学数学科学专业的博士研究生。我的研究方向主要集中在实验设计和偏好学习领域。自2024年夏季以来,我一直在JMP公司的实验设计与可靠性团队实习。实习期间,我参与过离散选择实验和软件测试相关的项目,这两个领域截然不同。关于我的介绍就到这里。
我先来概述一下今天的演讲内容。首先,在演讲的第一部分,我将谈谈我们暑假期间开发这款插件的动机。原因是,我们正在为 JMP 的 Easy DOE 项目进行一些可用性研究,试图了解不同用户群体(包括不同人口统计群体)的用户界面偏好。之后,在阐述了开发这款插件的动机之后,我将详细介绍并演示这款插件。最后,我将简要介绍如何使用 JSL 单元测试框架来测试这款插件,以验证我们开发的应用程序或插件。
这是第一部分,也是我们开发这款插件的动机。正如一些用户可能知道的那样,JMP 中有一个名为 Easy DOE 的程序。该程序旨在帮助用户完成实验设计和分析的整个过程。Easy DOE 的工作流程包含几个不同的部分。实验人员首先需要定义他们感兴趣的因素和响应变量。之后,他们选择要用于分析所收集数据的模型。选择模型后,他们就可以为该模型设计实验了。
实验设计完成后,他们可以进行实验,然后将收集到的数据输入到“数据录入”选项卡中。数据收集完毕后,他们可以分析模型。分析数据并拟合模型。最后,他们可以使用该模型进行预测,并根据需要选择最佳因子设置。最后,他们可以查看模型的汇总报告。
今天我们要重点关注的是“分析”选项卡。一些使用过 Easy DOE 的用户应该知道,“分析”选项卡的界面如图 2 所示。今年夏天,我们一直在研究如何改进“分析”选项卡的某些部分,使其更便于实验人员和 Easy DOE 用户使用。最终,我们提出了几个不同的用户界面版本供用户选择,并希望了解哪个版本最受欢迎。
我们设计的这个用户界面采用了因子结构。我们特别关注的是悬停帮助功能。悬停帮助包含几种不同的消息,用于告知用户模型的一些统计属性。这些消息包括“已输入消息”,用于指示某个项是否已输入到模型中(我们为此设置了两个版本);“显著性消息”,用于指示该项是否显著;以及“遗传消息”,用于解释为什么某个项即使不显著也会被包含在模型中。
通常情况下,存在一种称为“遗传”的特性,即如果交互项显著,但主效应不显著,我们仍然会包含主效应。最后,悬停帮助设置的另一个因素是悬停帮助的位置。它是位于置信区间上方,还是位于预览列上方?
我们想了解的是,用户最喜欢哪种设置?正如我刚才所说,我们考虑了四个因素。其中两个或三个因素有两个级别,而另一个因素有三个级别,因此悬停帮助设置的用户界面可能有多达 24 种不同的版本。
另外,Easy DOE 的用户群体中,很多都是新手或只有一些实验设计经验的人。但有时也会有经验丰富的实验设计人员使用 Easy DOE,他们可能将其用于个人学习或教学。Easy DOE 的用户群体涵盖了不同的人口统计特征。我们希望了解不同人口统计特征的用户群体偏好哪些悬停帮助设置,以便我们能够针对每个用户群体定制悬停帮助的设计。
我们希望通过情境离散选择实验框架来解决这个问题。接下来我将简要介绍一下这个框架。首先,我将谈谈数据收集过程。在情境离散选择实验中,我们会有一组参与者,以及这些参与者的一些协变量信息。例如,我们称之为协变量信息或情境信息。通常,它可以是用户的基本信息。
在这个框架下,我们向不同的参与者发放问卷,每个问题都要求他们比较两种或多种备选方案,并选择他们更倾向的方案。数据收集过程非常直观,也反映了人们在现实生活中可能做出的选择。
现在我将简要介绍一下情境离散选择实验的建模和分析。收集数据后,您可以对这些数据拟合一个效用模型。该模型不仅包含研究对象的相关因素(在本例中为悬停帮助设置),还包含来自参与者的情境信息。将这两者结合起来,可以了解不同用户群体(来自不同人口统计群体)对不同悬停帮助设置的偏好。最终,一旦拟合出这个效用模型,您就可以利用它来了解或找出每个人口统计群体最偏好的悬停帮助设计。
情境离散选择实验的一个重要组成部分是实验设计。我们如何选择要向参与者提出的问题?如果您熟悉常规离散选择实验,就会知道,为了设计出好的离散选择实验,通常需要一些关于用户偏好的先验信息。
在情境离散选择实验中,我们首先进行所谓的筛选研究。在筛选研究中,我们首先招募一定数量的参与者,并收集他们的情境信息或人口统计信息,然后让他们填写问卷并收集他们的偏好数据。基于筛选研究的结果,我们拟合一个模型来描述用户的偏好。之后,我们可以利用这个模型来了解不同人口统计群体之间的偏好。
因此,我们可以利用这个模型创建贝叶斯先验,进而为问卷设计贝叶斯D-最优设计。我们可以利用这些设计,针对不同的人口统计群体创建问卷,从而更高效地从每个群体中获取更多统计信息。这就是我们想要采用的方法……我们想要解决这个问题的方式。我们希望创建统计效率极高的问卷,发放给参与者,以便更有效地收集信息,了解不同人口统计群体的偏好。
接下来我将简单介绍一下这个插件的创建过程。首先,对于那些不了解的朋友,JSL 是 JMP 脚本语言。它允许用户扩展 JMP 的功能,例如运行常规的多步骤分析,或者将指定的模型拟合到每日生成的数据。JSL 真正实现了 JMP 功能的扩展。JMP 插件本质上就是一个 JSL 脚本,它可以扩展 JMP 的功能,其他 JMP 用户可以下载并使用它。
我们为什么要针对特定问题开发 JMP 插件?首先,我们当时正在进行多项可用性研究。我们会在不同的时间点进行同一项可用性研究,即针对悬停帮助设置的可用性研究。随着时间的推移,我们收集的数据越来越多,并利用这些数据来改进实验设计或发送给用户的问卷。此外,我们还在进行其他可用性研究,例如,针对用户界面不同因素的可用性研究。例如,其中一项可用性研究是关于“分析”选项卡上通知消息的配色方案和位置。
开发此插件的另一个原因是,创建这些情境离散选择实验可能很繁琐,因为通常需要计算先验均值和协方差矩阵,才能为每个组创建贝叶斯D-最优设计。我们发现,通过JSL脚本可以实现这一过程的自动化。
最后,这个情境离散选择实验框架可以应用于非常广泛的选择任务。它不仅限于可用性研究,还适用于任何需要用户在多个选项中表达偏好的研究。我们开发这个插件不仅是为了帮助我们自己,也是为了让其他人也能使用它来解决他们的问题。
我将简要介绍一下我们情境离散选择插件的工作流程。首先,用户或实验人员需要从筛选研究中收集数据。筛选研究应包含以下信息:您向参与者提出了哪些问题?参与者的属性是什么?个人资料属性是什么?您研究的对象有哪些因素,以及受试者的协变量。
获得这些数据后,就可以对数据拟合筛选模型。在筛选模型中,实验者需要指定两种效应:一是界面效应,二是受试者效应。在我们的案例中,界面效应指的是悬停帮助设置。这使得实验者能够创建一个效用模型。然后,使用 JMP 的选择分析平台来估计该效用模型。
完成上述步骤后,用户即可选择一个人口统计群体进行深入研究。他们通过选择每个受试者效应或背景因素的水平来实现这一点。这些水平的组合确定了一个待研究的群体。选定群体后,系统会为该群体构建贝叶斯D-最优设计或贝叶斯D-最优问卷,以便实验者能够以统计高效的方式对该群体进行进一步研究。
现在我将演示一下情境离散选择实验插件。我打开 JMP,然后进入“插件”菜单。我选择“数据表”。这个数据表包含一些信息……我快速展示一下它的样子。这个数据表包含了之前针对悬停帮助功能进行的可用性研究信息。您可以看到,其中包含诸如用户选择了哪个选项、呈现了哪些选项等信息。我们还有一些关于用户的情境信息,例如他们在实验设计方面的经验水平,以及他们使用 Easy DOE 的原因。是用于个人用途还是用于教学?
在这个……我打开这里。首先,我们要添加响应指示器,也就是用户做出的选择,还要设置选择集 ID 和主题 ID。然后,我们可以在这里输入个人资料效果,在我们的设置中,就是鼠标悬停帮助位置的那三条消息。如果需要,我们还可以添加交互效果。但现在,我只保留主效果模型。此外,我们还可以添加主题效果,例如经验水平,以及用户是教别人还是将 Easy DOE 用于个人用途。
您可以看到,这里的很多信息看起来都和选择分析平台的设置非常相似。点击“运行”后,后台会启动选择分析平台,并分析筛选研究的筛选模型。当然,我们可以像操作选择分析平台一样与它进行交互。例如,我们可以调出效用分析器,然后可以看到,经验丰富的用户(也就是那些正在指导他人的用户)更倾向于选择某个特定的遗传信息选项,也就是这里的第二个选项。
查看完这些信息后,我们可以调出这个组件,它会要求我们选择一个人口统计群体进行进一步研究。假设我正在进行这些研究,并且我想研究Easy DOE的专家用户,也就是那些在实验设计方面经验丰富的用户,我对他们在指导他人时的表现很感兴趣。我想制作一份问卷来了解这些专家用户的偏好。我点击“创建设计”,它会打开选择设计平台,并将我们在选择分析阶段或筛选研究阶段输入的信息自动导入到选择设计平台中。
我们有自己的属性,也有针对这个特定群体的模型,这是一个我们指定的主效应模型。最重要的是,利用筛选研究中的模型,我们能够计算出我们感兴趣的特定群体的贝叶斯先验均值和先验方差。
创建好先验信息后,我们就可以点击“创建设计”按钮,创建一个所谓的贝叶斯D-最优设计。这样,我们就得到了一个专门针对我们正在研究的特定群体而设计的实验设计。这个设计的构建充分考虑了我们之前掌握的关于该群体偏好的先验信息。现在,这个设计已经针对我们想要进一步研究的群体进行了定制。以上就是我对情境离散选择实验插件的演示。接下来我会关闭一些演示,然后回到幻灯片部分。
接下来,我要讲的最后一点是使用 JSL 单元测试框架测试插件。首先,对于那些不了解单元测试的人来说,什么是单元测试?单元测试是指测试软件应用程序的各个组件以识别错误。特别是,自动化单元测试允许频繁地对软件应用程序运行单元测试,以便在开发过程中识别和纠正新引入的错误。
具体来说,JMP 提供了一个名为 JSL 单元测试框架的单元测试框架,该框架专为 JSL 应用程序量身定制。该框架中最重要的函数是 `ut assert` 函数,它允许用户测试 JSL 应用程序的特定组件。用户会预设一个他们认为正确的输出,即预期值。然后,他们将预期值与应用程序的实际输出进行比较。如果两者匹配,则表示测试用例通过;如果不匹配,则表示测试用例失败。当用户编写包含 `ut assert` 函数的脚本并运行后,系统会返回一份报告,告知用户哪些测试用例通过,哪些失败,以便进行进一步的调查。
我们在情境离散选择实验插件中测试了不少功能。例如,我们测试了用于添加交互效果的“叉号”按钮。它是否正常工作?我们设想,如果选择两个特定的选项并点击“叉号”按钮,我们知道应该显示什么内容,因此可以将其与实际输出进行对比,以确保系统运行正常。
我们测试的另一项重要内容是,在选择要进行进一步研究的人口统计群体时,我们希望确保如果实验人员将某个选项留空,则会弹出一条消息。我们进行了测试,并确保此错误消息按要求弹出。
最后,这一点非常重要。我们想确保导入到选择设计器中的先验信息是正确的。我们对此进行了测试,并将其与选择分析平台的输出结果进行了比对。如果两者匹配,则说明我们已正确地将先验信息导入到选择设计器中;如果两者不匹配,则说明存在问题。值得庆幸的是,我们发现导入的先验信息是正确的。
现在,自动化单元测试最重要的作用之一就是在代码重构时发挥作用。自动化单元测试允许开发者重构代码并检查是否引入了任何错误。所谓代码重构,指的是在开发过程中对代码进行修改。如果你修改了代码,如何才能知道是否破坏了与修改内容无关的其他部分呢?
我们发现的一个例子是,该插件的一位测试用户发现,当某个上下文因素具有值标签时,该上下文因素的列表将无法正确显示。实际上,它根本不会显示。
我们回头修复了那个错误。但我们希望确保修复过程中不会引入其他问题。我们做到了这一点。我们通过重新运行单元测试脚本进行了验证。值得庆幸的是,运行单元测试脚本后,我们发现没有引入任何新的错误,这有助于确保我们没有破坏其他功能。正如您在图片右侧看到的那样,我们针对值标签问题提出的修复方案确实正确地解决了该问题。
单元测试非常重要,原因有三:首先,它可以帮助您发现代码中的错误;其次,它可以帮助您重构代码,确保没有引入其他错误;第三,随着 JMP 的更新,JMP 内部的某些机制以及某些平台可能会发生变化。有了单元测试脚本,您就可以在 JMP 更新后随时测试您的插件,确保 JMP 内部的某些更改是否影响了您的插件。
在今天的演讲结尾,我介绍了如何设计情境离散选择实验,以帮助我们了解不同用户群体对 Easy DOE 的用户界面偏好。然后,我演示了如何使用 JSL 脚本创建一个非常便捷的 JMP 插件来构建这些离散选择实验。最后,我讨论了在插件开发过程中或开发完成后进行单元测试的重要性,这有助于在开发过程中及开发完成后发现错误。
我的演讲到此结束。请问大家有什么问题吗?