注意: 虽然 JavaScript 对于本网站不是必需的,但您与内容的互动将受到限制。请启用 JavaScript 以获得完整体验。

用于协同药物发现的 Python

简介

阿斯利康是世界领先的制药公司之一。在全球拥有超过 54,000 名员工,它提供创新、有效的药物,旨在对抗癌症、控制疼痛、治愈感染以及对抗心血管、中枢神经、胃肠和呼吸系统的疾病。

发现一种新药通常需要十年以上的时间和超过 8 亿美元的费用。早期过程中的一个大问题是从大量可能的分子中识别出那些更有可能成为好药的候选药物。

计算化学家已经开发出许多预测分子特性的技术。这些技术可用于评估分子在胃中(对于吞服的药片)的稳定性、在血液中流动、穿过细胞膜并最终被分解和消除的可能性,并且不会对身体产生过大的毒性。

如果这些计算技术足够好,就不需要进行实际的实验。但是今天的计算机模型无法完全表征分子在体内的行为,也无法取代熟练的药物化学家的直觉。仍然必须在实验室中测试真实的分子,以观察它们的反应。

为了节省实验室工作的时间和金钱,实验化学家使用计算模型来缩小优秀候选药物的范围,同时还要验证要测试的候选药物并非彼此基本化学结构的简单变体。

需要改进的流程

药物识别的大部分工作实际上是通过分布在世界各地的许多研究小组之间的协作进行的。作为此过程的一部分,实验化学家将化合物列表发送给计算化学家,后者处理数据集并返回结果。

从历史上看,实验化学家被迫依赖计算化学家和其他人员来运行计算机预测。每种预测技术都需要运行一个单独的程序,有些是商业的,有些是公司内部不同小组开发的,每个程序都有自己的一组输入、选项、配置和故障行为。实验化学家通常没有接受过使用它们的培训,这意味着计算化学家被迫抽出时间来开发新技术,以运行常规模型。

2000 年,阿斯利康希望改进此流程,以便实验化学家可以自行进行更好的计算预测,并使计算化学家的研究能够更快地取得进展,并更快地进入实验室。

阿斯利康的首席科学家 Pierre Bruneau 在 Zeneca 工作期间研究过这个问题,该公司合并成立了阿斯利康。他开发了一个名为 H2X 的基于 Web 的界面,以二战期间使用的盟军导航系统命名。H2X 基于一个名为 Drone 的内部分子特性计算器。该系统使用 Perl 脚本,通过调用适当的预测程序来计算一些简单的分子特性,通常通过用 Perl、csh 或特定领域控制语言编写的包装器来实现。

选择 Python

使用 Drone 的 H2X 是一次成功的实验,很多人都在使用它。2001 年,阿斯利康决定进一步开发它,并请 Andrew Dalke 作为顾问,通过使其更健壮、可扩展和可维护来改进后端代码。Andrew 是计算化学和生物学中 Python 的知名倡导者,他让该小组相信 Python 是下一代后端(名为 PyDrone)的合适语言。

之所以选择 Python 来完成这项工作,是因为它是物理科学家(即没有计算机科学背景的人)可用的最佳语言之一。存在许多其他强大且富有表现力的高级语言,包括 Perl、Lisp、Scheme、Ruby、CAML 和 Haskell。在所有这些语言中,Python 是少数几种基于可用性研究以及使编程语言易于学习和使用的因素的语言之一。然而,Python 也是为解决专家程序员面临的现实问题而设计的。结果是一种可以很好地从化学家编写的小脚本扩展到软件开发人员编写的大型软件包的语言。

Python 的错误处理提高了健壮性

PyDrone 的第一个迭代将现有的 Perl 代码重构为更合适的函数、类和模块,同时将代码库转换为 Python。在不转移到 Python 的情况下重构 Perl 代码也会产生类似的架构结果,但是 Python 的显式错误处理和更强的类型检查有助于大大提高代码的健壮性。

当前版本的 PyDrone 使用大约 20 个不同的外部二进制文件和脚本来预测各种分子特性。当外部程序正常工作时,很容易将输出解析为所需的结果。但是,这些程序并非总是正常工作,没有完全记录,并且通常很难从外部确定所有可能的故障情况。为了弥补这一点,PyDrone 开发人员编写了测试来预测尽可能多的错误情况,但在部署后不可能排除其他意外的错误情况。

从在 Perl (Drone) 和 Python (PyDrone) 中处理此问题的经验来看,我们发现 Python 更擅长捕获多种类型的错误,并在已部署的应用程序中管理意外问题。这是两种语言处理错误处理方式的结果。例如,Perl 的 I/O 例程是安静的,必须显式检查故障,通常使用“or die”习语。一个认真负责的程序员总是会添加这些,但是它们会占用空间,容易被忘记,并且难以测试。与此相反,Python 函数是嘈杂的,当代码中出现问题时几乎总是会自动引发异常。

在用 Python 重写之后,我们最初认为这种嘈杂的行为是一种麻烦,因为 Python 不断引发异常并停止,而旧的 Perl 代码则继续运行。但是,我们很快发现几乎每个异常都表明之前未检测到的错误情况,我们需要为此添加新的错误处理代码。Python 帮助我们找到问题点,并防止我们将无声的错误引入我们的数据。

Python 为我们发现的一个错误案例是由一个外部预测程序引起的,该程序通常会返回一个数值错误代码,但在某些情况下,发现它会返回字符串“error”。在 Perl 中,字符串和数字会自动转换,例如字符串"123"变为整数123。不幸的是,Perl 也会转换非数字字符串,例如“error”,为0。因此,Drone 将“error”视为成功返回值,从而导致不正确的结果。Python 更强的类型一旦执行导致错误的罕见情况,就会发现该错误。

Python 帮助我们改进代码的另一种方式是,它在每个异常报告中都包含完整的堆栈追溯。我们发现这对于帮助我们了解问题的根源非常有用,而无需运行调试器或添加额外的代码检测。Python 的此功能在远程调试罕见情况时特别有用。Andrew 在美国,而 Pierre 在法国。当发生错误时,Pierre 包含追溯的电子邮件通常包含足够的信息来查明和解决问题。

使用 Python 添加强大的可扩展性

PyDrone 开发的下一阶段是提高其可扩展性。某些分子特性取决于其他特性。例如,分子的质量取决于其组成。旧的 Drone 代码使用一组“if”语句手动维护这些依赖关系,这些语句指定在执行分析期间应调用哪些预测例程,以及按什么顺序调用。在这种方法中,添加新的依赖关系很快导致了组合式的噩梦。

为了在 Python 中解决这个问题,我们开发了一个简单的规则库,它类似于 Python 字典。它包含一个数据缓存和一个从属性名称到预测函数的映射。如果请求的属性名称(字典键)在缓存中,我们会重用它。否则,我们会找到关联的函数,调用它来计算值,将结果存储在缓存中,并返回它。这些函数本身会获得一个指向属性管理器的引用,以便它们可以递归地请求任何其他需要的依赖项。要添加新的预测,我们会在函数表中注册新函数——并让函数本身处理依赖项。缓存是必需的,因为某些属性的计算成本很高,或者被许多其他属性需要。

Architecture of the Property Manager

属性管理器的架构 放大

由此产生的新架构对项目产生了简单而深刻的影响。我们现在拥有一个单一的系统,可以容纳所有当前和未来的预测方法,只计算产生请求结果所需的最小值,并且易于理解和维护。在我们用 Python 构建它之前,公司里有几个人认为根本不可能构建这样的系统。

Python 类型系统的好处

PyDrone 架构可以用多种语言实现,但 Python 的动态类型使得构建我们的属性管理器容易得多。一些分子属性是数字,另一些是字符串、列表和字典,还有一些是类实例。静态类型语言需要额外的麻烦来允许将混合返回类型插入到属性管理器中。即使是同样是动态类型的 Perl,也需要某种方法来区分对$标量, %哈希,或者@列表的引用。在 Python 中,它直接起作用了,我们可以在属性管理器字典中混合键的数据类型,而无需任何额外的努力。然而,如上所述,Python 同时提供了足够的数据类型检查来查找许多常见的类型不匹配错误。

使我们的属性管理器如此成功的一个因素是 Python 允许用户定义的类型模拟内置类型的行为。我们的属性管理器的行为非常像一个查找表,将属性名称映射到值,因此我们将其设计为模拟 Python 字典。在 Python 中,这是通过实现特定的特殊方法(例如)来完成的__getitem__(), __setitem__()等等。通过模拟字典,几乎所有其他对字典进行操作的 Python 函数都可以与我们的管理器一起使用。它还使代码更易于理解和调试,因为语法和调用点用法与人们的期望自然契合。

Python 还以其他方式促进了我们的属性管理器实现。用户请求的 PyDrone 的一个功能是能够使用基于现有属性的公式来描述新的预测。例如,一个公式可能看起来像

0.34 + (0.78*CLOGP) - (0.018*HBA) - (0.015*HB_TOT) - (0.11*MM_HADCA) - (0.017*MM_QON) + (0.012*VDW_POL_AREA)

其中变量是属性管理器中的键。这在 Python 中很容易实现,我们很难找到一种使它更容易的语言。Python 的数学表达式几乎与科学中使用的标准形式相同,因此我们可以使用 Python 的“eval”语句来解析和评估用户定义的表达式。由于我们的属性管理器的行为类似于 Python 字典,因此它可以(至少在理论上)直接作为在表达式求值期间用于变量查找的局部字典提供给 eval 语句。

事实证明,出于性能原因,Python 中的eval()实现只接受内置字典类型,而不接受模拟的映射类型,因此我们必须进行一些额外的技巧,使我们的按需依赖系统与方程式一起工作。尽管如此,整个实现还是相当容易的。

结果

PyDrone 大约花费了 3 个月的开发时间、另外 3 个月的质量保证和 3 周的文档编写时间,最终生成了大约 5600 行的成品 Python 代码。

总的来说,PyDrone 对于阿斯利康来说是一个巨大的成功。由于使用了 Python,我们能够快速轻松地开发出一个很棒的工具,它不仅非常易于使用,而且能够很好地适应新的预测方法。

我们在 Python 方面遇到的最大问题是阿斯利康中很少有人使用它进行开发。IT 部门更喜欢 Perl(系统人员)或 Java(架构人员),因此我们偶尔会收到将项目的部分内容重写为其中一种语言的请求。即便如此,我们发现开发人员对学习 Python 感兴趣,特别是当他们看到开发时间、精力、生成的代码大小和其他指标的比较时。

关于作者

Scott Boyer 是阿斯利康研发部门(瑞典,Mölndal)使能科学和技术部门的首席科学家。Scott 获得了科罗拉多大学博尔德分校的博士学位,曾在辉瑞和阿斯利康从事与建立最佳“类药物特性”相关的实验质谱和核磁共振研究。大约四年前,他转入了计算化学的“黑暗面”,现在领导着一个内部项目,旨在为阿斯利康所有 10 个发现研究站的实验化学家提供更多的建模工具。

Andrew Dalke 是 Dalke Scientific Software, LLC 的创始人,该公司是一家位于美国新墨西哥州圣达菲的软件咨询和合同编程公司。自 1992 年以来,Andrew 一直在开发计算化学和生物软件。他的主要关注点是将可用性设计和软件工程相结合,以开发科学家既使用又喜欢的软件工具。难怪他如此喜欢 Python。

Pierre Bruneau 是阿斯利康发现部(法国兰斯)癌症和感染研究领域的首席科学家。在斯特拉斯堡国立高等化学学院学习化学后,他最初加入了 Organon 研发部门,然后加入了阿斯利康(前身为 ICI Pharma,然后是 Zeneca)。在担任了几年药物化学家之后,Pierre 现在领导着法国实验室的当地物理化学和计算机小组,同时保持着对开发预测潜在药物分子理化特性和建立构效关系的方法和工具的兴趣。