用於協同藥物發現的 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 字典。它包含一個數據快取和一個從屬性名稱到預測函式的對映。如果請求的屬性名稱(字典鍵)在快取中,我們會重用它。否則,我們會找到關聯的函式,呼叫它來計算值,將結果儲存在快取中,並返回它。這些函式本身會獲得一個指向屬性管理器的引用,以便它們可以遞迴地請求任何其他需要的依賴項。要新增新的預測,我們會在函式表中註冊新函式——並讓函式本身處理依賴項。快取是必需的,因為某些屬性的計算成本很高,或者被許多其他屬性需要。

屬性管理器的架構 放大
由此產生的新架構對專案產生了簡單而深刻的影響。我們現在擁有一個單一的系統,可以容納所有當前和未來的預測方法,只計算產生請求結果所需的最小值,並且易於理解和維護。在我們用 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 現在領導著法國實驗室的當地物理化學和計算機小組,同時保持著對開發預測潛在藥物分子理化特性和建立構效關係的方法和工具的興趣。