好的。感谢各位收听今天的节目。我今天主要会聊聊JMP,具体来说,我会介绍如何在Amirys公司利用JMP实现分析工作流程的自动化,同时也会探讨更复杂的流程,以及如何利用JMP原生平台实现自动化或数据自动化。在正式开始之前,我想先简单介绍一下自己。我叫Stefan,是Amirys公司的数据科学副总监,拥有15年的生命科学行业经验,涉猎广泛。我曾在许多化学实验室、发酵实验室和高通量筛选团队工作过。我的工作经历涵盖质量管理、统计学、数据分析,当然还有现在的数据科学。我热爱一切与数据相关的事物,从数据存储到人们使用和访问数据的方式。目前,我为更广泛的AMRA科学社区提供工具和分析方法方面的支持。今天,我将主要介绍三个部分。我会先简单介绍一下我们将要使用的案例研究的背景和情况,我将用它来讲解一些自动化示例。我们会从最简单的开始。
我们如何使用 JMP 来自动化运行分析工作流程?这些分析可能是您日常进行的,而您希望提高其效率。在最后一部分,我们将探讨更高级的自动化,即更复杂的工作流程。我们可能会研究如何分析更广泛的技术团队使用的这些工作流程。如何将其推广,以同时支持数据处理和导入以及分析环节?我们今天的案例研究来自我所在的公司 Amirys。简单介绍一下 Amirys。我们是一家合成生物学公司。我们专注于酵母编程和工业发酵,为酵母提供糖分,并将糖转化为纯净的成分或化学品。我们的总部位于加利福尼亚州埃默里维尔,大部分生产都在巴西进行。我们今天的案例研究并非着眼于生产方面,而是侧重于研发方面。在埃默里维尔,我们拥有许多高度自动化的实验室,我们称之为筛选和分析实验室,我们每月在这些 96 个壁板中筛选数十万株菌株。
您可以看到图片上有一些条形码标记的培养板。这些就是我们用作小型发酵罐的。这是我们测试这些菌株产量的第一步,看看它们产的是什么。我们正在寻找这些菌株的特定表型。我们在这些96孔板中培养它们,然后使用一整套不同的分析方法来生成测量数据,通常是对这些孔进行多维测量。我们还有很多内部数据库,很多数据以及相关的元数据都存储在应用程序数据库和数据仓库中,我们可以使用JMP等工具访问这些数据。这就是JMP的作用所在。当然,筛选的最后一步是筛选大量的菌株,生成大量数据。现在我们需要理解这些数据,做出决定,选择哪个菌株进行反应器发酵,并有可能在巴西进行生产。
我们将从 JMP 中的简单自动化开始。今天我想做的是,如果你以前从未在 JMP 中进行过自动化操作,或者从未使用过这些平台,我希望能够以一种易于理解、相对无需编写代码的方式向你介绍它们,并让你对这些平台的构建方式有一个基本的了解,以及我在自学和向他人学习使用这些自动化平台的过程中所学到的东西。
我常说,如果某件事重复执行超过 10 次,那它可能就值得自动化了。如果你是自动化新手,我认为最好的起点就是从你自己的分析入手。这样做的好处在于,或者如果你对分析结果非常熟悉,就可以给自己提供反馈。当然,这通常比为更大的团队进行更广泛的分析要简单得多。在我们的例子中,我们将进行一个非常简单的测量——在培养皿上进行单次测量。我们从预培养阶段到生产阶段,对培养皿进行连续的扩增。在第二个培养皿中,我们进行单次测量。在这个模拟示例中,我们会说:“嘿,我们一直在重复进行完全相同的实验。”每次进行实验时,我们都会将数据导入 JMP。我们会添加一个计算列。然后,我们会根据该列进行筛选,并生成一些可视化和统计测试,以帮助我们做出决策。做一次,花不了多少时间,但如果你每天都重复这样做,时间就会累积起来。
在深入探讨自动化部分之前,我想先简单提一下结构化数据,这实际上是自动化的先决条件。如果大部分标准化和结构化工作都在上游完成,比如在收集数据并将其导入数据库(或 CSV 文件)时,你的工作将会轻松许多。在我们的例子中,数据库本身就已经是结构化的了。当然,你可以在 JMP 中完成很多数据处理工作,而且通常需要根据你所使用的应用程序或分析方法来选择合适的工具。但你真的应该认真思考一下数据的来源是什么?你越早处理数据,效果就越好。如果你使用的是数据库数据,我建议使用查询构建器。今天我们就不深入探讨这方面了。这是我的总体建议。JMP 脚本编写的基础是日志。无论你是否意识到,JMP 默认都会记录你的操作,包括你点击用户界面时执行的 JSL 代码和脚本。如果你打开“视图”菜单,点击“日志”,即可查看日志,其中记录了你执行的大部分步骤。
点击任何一个步骤,都会显示用于执行该步骤的 JSL 代码。在这个例子中,我们正在执行添加计算列的第一步,我已经点击并高亮显示了那里的 JSL 代码。这是一种快速查看每个步骤正在执行的 JSL 代码的方法,您可以直接从日志中运行该代码或重新运行之前的代码。话虽如此,我并不建议您在日志中尝试真正实现自动化操作。它只是代码的来源之一。您可以将日志中的内容提取到例如数据表中的一种方法是使用数据表脚本。长期以来,这都是在 JMP 中实现分步自动化的方法。在这个例子中,我打开了这个数据表,点击了红色热点,生成了一个新脚本。这会弹出一个空白窗口,我直接从日志中粘贴了两个步骤的代码:第一步创建新列,第二步为该列设置公式。
你还可以进一步清理代码。这完全是可选的。但在后面的章节中,当我们开始讨论更复杂的示例时,你可能需要思考:如何让我的代码更易于维护或更简洁?在这个例子中,我们进行了两步清理。第一步,我们删除了冗余的数据表引用。第二步,我们进一步压缩了代码,不再重命名第 21 列,而是从一开始就使用正确的名称。每个方框都能正常工作,它们的功能完全相同。在这种情况下,你不会注意到性能上的任何差异,但它可以使代码更简洁、更易于维护。如果你是 JSL 新手,看到这段代码可能会想:这到底是做什么的?你可以将这些代码粘贴到你喜欢的 LLM 工具中。我们使用 Copilot、ChatGPT 等等。如果你有权限访问 JMP 学习机器人,可以向它询问“嘿,这段代码是做什么的?”。它通常能让你很好地了解这段代码的作用。
我们从日志中提取了数据,或者说,从日志中提取了代码,并将其粘贴到数据表脚本中。这是最手动的自动生成 JSL 的方法。您可以在这里看到它。正如我们命名的那样,第一步是添加计算列。在大多数平台上,还有更多直接的方法来生成这些表脚本并保存生成特定输出的脚本。许多平台在红色热点下方提供了这些选项。在红色热点下方,您可以一直向下滚动。有一个“保存脚本”选项,它提供了许多选项。您可以将其保存到剪贴板,也可以直接保存到数据表(我们将采用这种方式),以及其他选项。这使得直接从用户界面自动生成 JSL 变得非常简单。我们将其保存到数据表中。在这种情况下,我们所做的只是重命名该脚本,进行第二步,即数据筛选,然后继续进行分析。我们可以在最后一步中完成这项工作,即生成 Y 乘 X 图,并且我们还应用了 Dunnett 检验和参考组。
再次,我们点击红色热点,选择“保存脚本”,然后将其保存到数据表中。我们创建的就是这个伪工作流。它包含一个三步自动化流程:首先,在表中添加一个计算列;其次,添加或应用一个数据筛选器;最后,使用邓内特检验进行单因素方差分析。这引导你进入表格脚本的使用领域,这种情况持续了很长时间,直到 JMP 16 或 17 版本左右,工作流功能才出现。工作流真正实现了表格脚本功能的升级,增加了更多功能。工作流是一个全新的平台,它是 JMP 中的一个独立平台。你可以通过“文件”、“新建”、“工作流”来访问它。它提供了许多功能,不仅可以简化工作流的开发,还能显著提升最终用户的使用体验。例如,你可以点击一个按钮来运行工作流中的所有步骤。 JMP 提供步骤录制功能,可以记录您在 JMP 中的操作并自动将其添加到工作流程中。您可以直接在工作流程中注释脚本,还可以添加逻辑门、交互功能、用户提示等,功能非常丰富,今天我们当然没有时间一一介绍。
但我会展示一些示例,尤其是在更高级的版本中。现在我们可以使用这些表格脚本,这样我们就得到了一个伪工作流。我们可以想象一下,这可能是在工作流出现之前创建的,JMP 添加了工作流平台,现在我们又将其添加到了工作流构建器中。我在这里所做的只是添加了三个步骤。我粘贴了每个步骤的 JSL 代码,您可以看到,工作流中的三个步骤与数据表脚本中的完全相同。我将在这里简要演示一下这些步骤在我们真实数据或演示数据中的效果。在第一个示例中,我们有结构化数据。我们有一些测量值。我们想要再次执行这三个步骤。我们可以看到,在这种数据表脚本方法中,您只需逐个点击即可。我点击了它。现在我们添加了这个计算列。我们应用了一个数据过滤器,它会弹出并应用此过滤器,然后我们为这个特定实验生成一个单因素分析。
很简单,对吧?这些方法都有效。对于像这样的简单操作来说,这些方法非常有效。你需要切换到工作流吗?你需要进行更复杂的操作吗?不一定。如果这个方法有效,那就很好了。我们可以重置它,你会看到我在这里需要手动操作。我们要清除行状态,确保数据筛选器已关闭,然后就可以查看工作流了。这同样是三个步骤。这里更方便的是,我现在可以自动查看代码。这里不行。在这里,我必须右键单击,选择“编辑”,然后在新窗口中查看定义。而在这个选项中,我可以看到每个步骤的代码。在这里,我可以点击播放,它会同时执行所有三个步骤。我看到了漂亮的绿色对勾,告诉我它运行没有错误。你会看到我们有了新的列。我们应用了筛选器,并且打开了相同的分析。界面更清晰了。下一节,我们将更深入地探讨使用该工作流程的其他附加功能。
我想简单提一下演示中的录制按钮,它非常棒,尤其适合那些不熟悉 JSL,甚至完全不懂编程的人,这是创建自动化流程最简单的方法。你只需点击录制按钮,我在这个平台上做的任何操作都会被记录到工作流程中。我举个例子,绘制一个测量分布图,假设它代表一些有意义的数据。回到工作流程,你会看到这里多了一个步骤,也就是我们的 JSL 脚本。我可以重命名它、添加注释、修改它等等。工作流程构建器的一个非常棒的功能就是这个录制按钮。我们再深入探讨一下。也许你已经为某个特定应用场景实现了自动化,或者它适用于某种实验类型。那么,如何将它应用到更复杂的流程中呢?这就是我们之前遇到的问题。
在 Amirys,现实情况是我们需要处理很多不同的实验类型,我们希望尽可能用最少的流程来支持它们。我们不想为每一次迭代都创建一个独特的流程,因为那样维护起来会非常困难,开发起来也会非常棘手。当你进行更高级的开发时,我建议你使用 JMP 项目来组织我所谓的开发环境。这个建议是我在 JMP 社区的某个视频中看到的。自动化这些复杂操作的一大痛点在于,你会看到各种各样的数据表、窗口等等,它们会不断弹出,难以管理。如果你使用项目,你可以把它当作开发环境的封装层,最终也能更好地利用这个工具。
这里我打开了一些默认的项目平台,比如工作区和内容。我添加了一个日志作为占位符。这样,工作流打开的任何新窗口都会以新标签页的形式打开,而不是在我的桌面上以新窗口的形式打开。当然,你也可以使用这个日志来记录文档或说明。右侧是我实际构建的工作流。底部我还添加了我的日志。
如果我需要进行一些故障排除,或者需要查看错误消息的更多详细信息,日志就在那里,我可以直接在一个窗口中完成所有操作。这也是我在该项目中演示此工作流程的方式。我收到的用户反馈普遍积极,他们不喜欢表格和可视化图表过多。当我们谈到自动化通用化时,我们希望瞄准高影响力应用,因为自动化通用化并非易事,无论是数据自动化还是物理自动化,如果您曾在实验室或制造行业进行过相关工作,对吧?这需要大量的精力、金钱、时间和人力。一般来说,如果您希望自动化数据工作流程,请优先考虑将其应用于标准化工作流程,或者将其作为推动标准化的一种方式。例如,您可以说:“嘿,如果我们标准化了这些流程,我们也可以自动化您每天都在做的那些非常繁琐的数据处理工作。”
数据工作流程通常需要一定的灵活性,这可能是流程本身的局限性,也可能是因为人们查看数据的方式不同。这时,你可以逐步实现自动化。这正是 JMP 的强大之处,因为经常有人问我,既然要自动化,为什么不直接用 Python 呢?为什么不直接用纯代码平台来实现自动化呢?问题在于,一旦完全基于代码,就会给用户设置很高的准入门槛。除非你能实现端到端的自动化,否则如果流程进行到某个阶段,用户需要接手,而你又要求他们“精通 Python”,那么即使是像我合作的科学家群体这样技术水平很高的群体,也会面临巨大的准入门槛。
JMP 的确很棒,因为它可以自动化第一步,之后最终用户就可以直接在 JMP 中使用。他们可以通过用户界面轻松上手,随心所欲地操作,充分发挥自动化功能的优势。当然,我们希望找到高价值的机会,因为这确实需要付出努力。就我们而言,我们当时在研究这些微孔板实验,并与科学家们交流,询问他们“获取这些数据需要花费多少时间?” 我们注意到,很多人都在手动操作,重复复制粘贴等繁琐步骤。
我们团队有17位科学家。我们做了一些调查,估计我们花在所有这些工作上的时间大约相当于一个人的时间,而且这时间成本相当高。这对我们来说是一个机会,让我们意识到:“嘿,很多工作看起来都是手动完成的,重复性高,而且完全可以自动化。” 让我们尝试一下。你肯定会遇到的最大挑战是复杂性。当我们考虑自动化时,有两个维度。一个是工作流程中的总步骤数,另一个是每个步骤的变体数。变体实际上就是路径上的一个分支。我喜欢右边的这张图,因为它很容易演变成一个指数级增长的问题,你需要解决某个流程的太多可能的迭代或变体。你必须考虑如何着手处理这个问题,你需要问自己:它是否可控?如果不可控,你能做些什么来让它可控?你可以像我们提到的那样,通过标准化来消除差异,或者说,“嘿,这种特殊情况无法通过数据分析来解释。”
您甚至可以添加错误消息,正如您在工作流程中看到的那样。您还可以使用自动化退出机制来省略步骤。这就是我之前提到的,让用户接管操作。如果存在非常精细、独特的质量控制步骤,您可以暂停工作流程,让用户完成他们需要做的任何操作,然后他们可以从那里恢复工作流程。您有很多选择需要考虑,但毫无疑问,在考虑自动化时,周密的计划对您大有裨益。在我们的案例中,我们研究了这些印版工艺,这也是我最初给出的例子。如果我们进行单次印版复制,我们会进行一次测量,我们将此过程称为第一次复制。
当我们开始研究不同实验之间的差异时,我们发现,“嘿,实际上,有时我们会从这个板上进行两次测量,而不仅仅是一次。” 有时,我们还会从串行传播中的第一个板上进行测量。有时,我们会对两个板都进行两次测量。有时,我们实际上是将板分开。我们不只是简单地进行一对一测量,而是进行一对二或一对多的测量。
我们正在对这些数据进行测量。有时我们会将它们分开,分别对两组数据进行不同的测量。我并不指望你们能记住这些细节,但我想要说明的是,我们的流程存在很大的差异。我这里只是举几个例子。我们的流程有几十种不同的变体。我们刚才关注的是流程本身的复杂性,也就是我们实验室生成数据的流程。我们甚至还没开始思考,人们查看和分析数据的方式有多标准化?他们使用哪些统计检验?他们是使用汇总指标,还是使用中位数或平均值?
复杂性可能很快就会变得非常棘手,所以事先做好调研至关重要。我们一直在研究一个仍在开发中的项目,虽然已经部署,但我们仍在不断迭代改进。我的另一个建议是,先确定哪些功能是真正有用的,然后定期从最终用户那里收集反馈。我们针对平面分析提出了这种通用方法。
这就是一个更复杂的工作流程。我们实际上是在调整数据库中的数据,并直接提示用户根据他们要查找的特定实验筛选数据。我们进行了大量数据处理,修复数据类型、命名规则,并确保这些方面保持一致。我们根据该流程拆分数据。我们看到了串行传播。我们需要了解哪个测量值与哪个板相关联。我们进行一些检查,检查是否存在我们不支持的流程?是否存在此自动化流程不支持的测量值?如果存在错误,我们会抛出错误并向用户显示消息。我们围绕透视进行更多数据处理。我们甚至为用户提供添加离线数据的选项。用户可能对他们的基因型进行了手动注释。最后,我们生成一组默认的可视化和分析。
我再详细解释一下,给大家演示一下。就像我刚才展示的,我们现在在项目里。这里有工作区内容,有日志,还有工作日志。我打算把工作日志关掉,因为演示中不需要它,而且它占用了屏幕宝贵的空间。
但我们这里有工作流程。我已经尽可能地将这些步骤简化到易于理解的程度,以便您明白每个步骤的作用。您还可以看到,您可以启用或停用某些步骤,在本例中,仅用于本次会议。我们只是导入静态数据,因为我们不会连接到公司数据库来提取真实的实验数据。我们这里直接包含了原始数据。您还会注意到这里的一些逻辑门,对吧?这些 if/out 语句允许您设置逻辑开关或不同的路径,也就是不同的分支,例如,如果数据符合特定条件,则执行此操作;否则,执行其他操作。
我这就运行。我们正在导入数据。我这里有一句可能有点阴阳怪气的话,其实就是……你可以设置一些小弹窗来给用户反馈。我说,很好。你们的电脑面板只有B测量数据,对吧?这是我们唯一允许的。干得好。他们点击了确定。程序继续运行。现在我们给他们一个提示。提示是:嘿,你想添加手动创建的元数据吗?
这通常是该数据集的基因型数据。第一次运行时,我直接点击“否”。实际上,这里没有任何数据。就像,好的,我们先运行一遍。现在我们已经生成并运行了所有内容。所有项目都已完成,并显示绿色对勾。在左侧,您可以看到一些数据表,以及一些默认的性能可视化图表,还有我们对菌株选择板进行的归一化处理。
现在,这里真正巧妙的地方在于,我可以点击这个按钮,也就是重置按钮,它会关闭工作流打开的所有内容,并将其重置到开头。现在我已经重置了。您可以看到我们回到了日志页面,以及开头的小箭头。我现在可以再次运行它。在同一个提示中,我选择“是”。这将引导我进入一个略有不同的路径。我选择“是”,我想添加手动数据。现在它会弹出另一个提示,询问我想使用哪一列来连接数据?我将使用这个 X 编号,它是一个唯一标识符。
我们使用了四种菌株。点击确定。它会提示:“嘿,我在你的数据集中找不到这个。” 当然,它找不到,因为这是我自己的离线数据。我要去我的电脑上,找到它。在这个例子中,我把它存储在一个 CSV 文件中,我们要把它合并,然后运行脚本。你会注意到,我们最终得到了相同的结果。我们有了这个标准化。我们有了这个用于测量的图表构建器箱线图可视化。但我们所做的是,我们现在还添加了一些额外的……这些列,启动子突变,以及其他一些信息,这些信息原本存在于离线数据中,现在我们已经将它们合并到主数据中,而之前并没有这样做。
这些通用工作流程功能非常强大。发布这些工作流程时,我也会将其保存到一个项目中。这就是项目中的工作流程。我会在这里添加用户文档以及任何相关的内部文档的超链接。用户访问此页面后,点击播放按钮,系统会提示他们输入实验 ID。这将动态地改变导入的数据,然后流程会按照此流程运行。
你会注意到这里还有一些关于抛出错误之类的操作。这是为了应对我们不支持的特定情况,或者可能遇到意料之外的实验类型。另外,如果你要进行概括,需要注意的是,默认情况下,很多表和列的引用都是自动生成的。无论你是使用记录按钮,还是使用平台上的红色下拉菜单,这些引用通常都是明确的,会显示“数据表名称”和“列名称”。但当你进行概括时,这种做法并不总是适用。
你可能会发现自己需要学习并手动修改 JSL 代码,其中一项内容是关于列和数据表引用,如何管理它们,以及如何使它们动态化。我导入的列数可能会根据用户导入的内容而变化,我需要能够支持这种情况。一旦你开始接触这方面,几乎肯定需要编写一些 JSL 代码。但同样,JMP 可以帮你完成 90% 的工作,包括大量的流程记录、日志记录,以及所有那些红色热点和脚本保存选项。
当你需要编写 JSL 代码时,你会去哪里找答案?我使用过很多不同的数据工具、数据软件和编程语言。JMP 的学习资源非常棒。它本身就内置了脚本索引。现在,你还可以使用 LLM 的辅助功能来排查 JSL 问题,甚至生成 JSL 代码。我认为它不如 Python 之类的语言好用,部分原因是它的训练数据集比 Python 的要小得多,但它仍然可以帮助你入门。
这正是JMP社区真正独一无二之处。一定要利用论坛。举个今年早些时候的例子。我发了这个问题,最让我印象深刻的是时间。我是晚上7点15分提交的。Jim,这位大神,当天晚上9点45分就回复了。第二天早上,Mark在大约12小时后也回复了。不到24小时,我就得到了两位专家的解答。每次我在论坛发帖,都能得到这样的回复。
特别感谢大家,尤其是Mark和Jim。我经常看到你们的名字,但其实论坛上每个人都用这些名字。它们对你们的学习非常有价值。最后,我想总结一下,并鼓励大家审视一下自己的组织、团队、实验室,无论你们的工作是什么,都要寻找能够应用通用自动化的高影响力机会。就我们而言,我们发现某个领域,我们每个实验都要花费数小时,一个月内要运行50多个这类实验。那几乎占用了一个人的全部时间,他要花在处理这些数据上。
一旦你确定了目标,就要管理和规划应对复杂性。我们在实验设计和筛选过程中遇到了很多变数。我们通过以下方式解决了这个问题:一方面,我们赋予用户更多选择权;另一方面,我们限制了报告支持的内容;同时,我们也充分利用 JMP 的用户界面,告诉用户“接下来就看你们的了”。你们仍然可以按照自己喜欢的方式进行可视化。这促使我们实施这些高级工作流程,从而消除重复性任务,并将其作为标准化分析的一种手段。我经常看到的情况是,我们喜欢把事情标准化,但一旦涉及到数据分析,我们就把它看作是手工操作。
这固然有一定道理,但也存在一些可以制定最佳实践的机会。我们应该如何看待这些数据?针对这些数据所呈现的特征,应该采用哪种统计检验方法?这为您提供了一个机会,可以将这些方法编入类似 JMP 工作流程之类的工具中。