Python 助力協同藥物研發
引言
阿斯利康是全球領先的製藥公司之一。公司在全球擁有超過 54,000 名員工,提供創新、有效的藥物,旨在抗癌、止痛、治療感染以及對抗心血管、中樞神經、胃腸道和呼吸系統疾病。
發現一種新藥通常需要十多年時間,耗資超過 8 億美元。在這個過程的早期,一個大問題是如何從浩瀚的潛在分子中識別出那些更有可能成為好藥的候選分子。
計算化學家已經開發出許多技術來預測分子性質。這些技術可以用來評估分子在胃中(對於吞服的藥片)的穩定性、在血液中傳輸、穿過細胞膜並最終被分解和清除的可能性,所有這些都不能對身體造成太大毒性。
如果這些計算技術足夠好,就沒有必要進行實際實驗。但目前的計算機模型無法完全表徵分子在體內的行為,也無法取代經驗豐富的藥物化學家的直覺。真正的分子仍然需要在實驗室中進行測試,以觀察它們的反應。
為了節省實驗室工作的時間和金錢,實驗化學家使用計算模型來縮小良好藥物候選者的範圍,同時驗證待測試的候選者並非彼此基本化學結構的簡單變體。
流程改進需求
許多藥物識別工作實際上是透過分散在世界各地的許多研究小組之間的協作進行的。作為此過程的一部分,實驗化學家將化合物列表傳送給計算化學家,後者處理資料集並返回結果。
歷史上,實驗化學家不得不依賴計算化學家和其他工作人員來執行計算機預測。每種預測技術都需要執行一個單獨的程式,有些是商業的,有些是由公司內部不同團隊開發的,每個程式都有自己的一套輸入、選項、配置和故障行為。實驗化學家通常沒有足夠的培訓來操作它們,這意味著計算化學家不得不從開發新技術的工作中抽出時間來執行常規模型。
2000 年,阿斯利康希望改進這個流程,以便實驗化學家能夠自行進行更好的計算預測,從而使計算化學家的研究能夠更快地推進,並更快地進入實驗室。
阿斯利康的首席科學家 Pierre Bruneau 在 Zeneca(後來合併成為阿斯利康)工作期間曾研究過這個問題。他開發了一個名為 H2X 的基於網路的介面,其名稱來源於二戰期間盟軍使用的導航系統。H2X 基於一個內部分子性質計算器,名為 Drone。該系統使用一個 Perl 指令碼,透過呼叫適當的預測程式(通常透過 Perl、csh 或領域特定控制語言編寫的包裝器)來計算一些更簡單的分子性質。
選擇 Python
使用 Drone 的 H2X 是一次成功的實驗,並被許多人使用。2001 年,阿斯利康決定進一步開發它,並聘請 Andrew Dalke 作為顧問,透過使其更健壯、可擴充套件和可維護來改進後端程式碼。Andrew 是計算化學和生物學領域 Python 的知名倡導者,他 MfL 說服了團隊,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 字典。它包含一個數據快取和從屬性名稱到預測函式的對映。如果請求的屬性名稱(字典鍵)在快取中,我們就重用它。否則,我們找到相關的函式,呼叫它來計算值,將結果儲存在快取中並返回它。函式本身被賦予對 Properties 管理器的引用,因此它們可以遞迴地請求任何額外需要的依賴項。要新增新的預測,我們在函式表中註冊新函式——並讓函式本身處理依賴項。需要快取是因為某些屬性計算成本很高或許多其他屬性都需要它們。
屬性管理器的架構 放大
由此產生的新架構對專案產生了簡單而深遠的影響。我們現在擁有一個單一的系統,可以適應所有當前和未來的預測方法,它只計算獲得所需結果所需的最小量,並且易於理解和維護。在我們用 Python 構建它之前,公司中的幾個人曾認為根本不可能構建這樣的系統。
Python 型別系統的優勢
PyDrone 架構可以用許多語言實現,但 Python 的動態型別使得構建我們的屬性管理器變得容易得多。有些分子性質是數字,有些是字串,有些是列表和字典,還有一些是類例項。靜態型別語言將需要額外的麻煩才能允許混合返回型別插入到屬性管理器中。即使是同樣動態型別的 Perl,也需要某種方法來區分對$scalar, %hash或@list的引用。在 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 周的文件編寫時間,最終產生了大約 5,600 行完成的 Python 程式碼。
總體而言,PyDrone 對阿斯利康來說取得了巨大的成功。由於使用了 Python,我們能夠快速輕鬆地開發出一個功能強大且易於使用、能夠很好地適應新預測方法的工具。
我們使用 Python 遇到的最大問題是,阿斯利康內部很少有人將其用於開發。IT 部門更喜歡 Perl(系統人員)或 Java(架構人員),因此我們偶爾會收到將專案部分用這些語言之一重寫的請求。即便如此,我們發現開發人員對學習 Python 感興趣,特別是當他們看到開發時間與精力、最終程式碼大小和其他指標的比較時。
關於作者
Scott Boyer 是阿斯利康探索研發部(瑞典默恩達爾)賦能科學與技術部門的首席科學家。Scott 獲得了科羅拉多大學博爾德分校的博士學位,並曾在輝瑞和阿斯利康工作,從事與建立最佳“藥物樣性質”相關的實驗質譜和核磁共振研究。大約四年前,他轉向了計算化學的“黑暗面”,現在負責內部專案,旨在為阿斯利康所有 10 個探索研究站點的臺式化學家提供更多建模工具。
Andrew Dalke 是 Dalke Scientific Software, LLC 的創始人,這是一家位於美國新墨西哥州聖達菲的軟體諮詢和合同程式設計公司。Andrew 自 1992 年以來一直從事計算化學和生物學軟體的開發。他的主要重點是結合可用性設計和軟體工程,開發科學家既喜歡使用又樂於使用的軟體工具。他如此喜歡 Python 不足為奇。
Pierre Bruneau 是阿斯利康探索部(法國蘭斯)癌症和感染研究領域的首席科學家。在斯特拉斯堡國立高等化學學院學習化學後,他最初加入了 Organon R&D,隨後又加入了阿斯利康(前身為 ICI Pharma,後為 Zeneca)在法國蘭斯的分公司。在擔任藥物化學家多年後,Pierre 現在領導法國實驗室的當地物理化學和計算機小組,同時保持對開發預測物理化學性質和建立潛在藥物分子結構-活性關係的方法和工具的興趣。
