Hinweis: Obwohl JavaScript für diese Website nicht unbedingt erforderlich ist, werden Ihre Interaktionsmöglichkeiten mit den Inhalten eingeschränkt sein. Bitte aktivieren Sie JavaScript für das volle Erlebnis.

Python für kollaborative Medikamentenentwicklung

Einleitung

AstraZeneca ist eines der weltweit führenden Pharmaunternehmen. Mit über 54.000 Mitarbeitern weltweit bietet es innovative, wirksame Medikamente zur Bekämpfung von Krebs, zur Schmerzkontrolle, zur Heilung von Infektionen und zur Bekämpfung von Krankheiten des Herz-Kreislauf-, Zentralnerven-, Magen-Darm- und Atmungssystems.

Die Entdeckung eines neuen Medikaments dauert oft über ein Jahrzehnt und kostet mehr als 800 Millionen US-Dollar. Ein großes Problem zu Beginn des Prozesses ist die Identifizierung der Kandidaten, die aus dem riesigen Universum möglicher Moleküle mit höherer Wahrscheinlichkeit gute Medikamente sind.

Computerchemiker haben viele Techniken zur Vorhersage molekularer Eigenschaften entwickelt. Diese können verwendet werden, um die Wahrscheinlichkeit zu bewerten, dass ein Molekül im Magen stabil ist (für geschluckte Pillen) und dass es durch den Blutkreislauf reisen, die Zellmembran durchqueren und schließlich abgebaut und ausgeschieden werden kann, ohne dabei zu toxisch für den Körper zu sein.

Wenn diese computergestützten Techniken gut genug wären, gäbe es keine Notwendigkeit für tatsächliche Experimente. Aber heutige Computermodelle können das Verhalten eines Moleküls im Körper nicht vollständig charakterisieren, noch die Intuition eines erfahrenen Pharmazeuten ersetzen. Echte Moleküle müssen immer noch im Labor getestet werden, um zu sehen, wie sie reagieren.

Um Zeit und Geld bei Laborarbeiten zu sparen, verwenden experimentelle Chemiker computergestützte Modelle, um das Feld guter Arzneimittelkandidaten einzugrenzen, und stellen gleichzeitig sicher, dass die zu testenden Kandidaten keine einfachen Variationen voneinander sind, was ihre grundlegende chemische Struktur betrifft.

Prozessverbesserungen erforderlich

Ein Großteil der Arbeit zur Identifizierung von Medikamenten findet tatsächlich durch die Zusammenarbeit vieler Forschungsgruppen statt, die weltweit verstreut sind. Als Teil dieses Prozesses senden experimentelle Chemiker eine Liste von Verbindungen an den Computerchemiker, der mit dem Datensatz arbeitet und die Ergebnisse zurücksendet.

Historisch gesehen waren experimentelle Chemiker gezwungen, sich auf Computerchemiker und anderes Personal zu verlassen, um Computerprädiktionen durchzuführen. Jede Prädiktionstechnik erforderte die Ausführung eines separaten Programms, einige kommerziell und andere firmenintern von verschiedenen Gruppen innerhalb des Unternehmens entwickelt, und jedes Programm hatte seine eigenen Eingaben, Optionen, Konfigurationen und Fehlerverhalten. Ein experimenteller Chemiker verfügte in der Regel nicht über die Ausbildung, um damit zu arbeiten, was bedeutete, dass die Computerchemiker gezwungen waren, ihre Arbeit an der Entwicklung neuer Techniken zu unterbrechen, um Routine-Modelle auszuführen.

Im Jahr 2000 wollte AstraZeneca diesen Prozess verbessern, damit experimentelle Chemiker selbst bessere computergestützte Vorhersagen treffen konnten und die Forschung der Computerchemiker schneller voranschreiten und schneller ins Labor gelangen konnte.

Pierre Bruneau, ein Principal Scientist bei AstraZeneca, hatte an diesem Problem gearbeitet, während er bei Zeneca tätig war, das zu AstraZeneca fusionierte. Er entwickelte eine webbasierte Schnittstelle namens H2X, benannt nach den alliierten Navigationssystemen des Zweiten Weltkriegs. H2X basierte auf einem firmeninternen Moleküleigenschaften-Rechner namens Drone. Dieses System verwendete ein Perl-Skript, das einige der einfacheren molekularen Eigenschaften berechnete, indem es das entsprechende Prädiktionsprogramm aufrief, meist über einen Wrapper, der in Perl, csh oder einer domänenspezifischen Steuersprache geschrieben war.

Python gewählt

H2X mit Drone war ein erfolgreiches Experiment und wurde von vielen Leuten genutzt. Im Jahr 2001 beschloss AstraZeneca, es weiterzuentwickeln und holte Andrew Dalke als Berater hinzu, um den Backend-Code zu verbessern, indem er robuster, erweiterbarer und wartbarer wurde. Andrew, ein bekannter Befürworter von Python in der computergestützten Chemie und Biologie, überzeugte die Gruppe, dass Python die geeignete Sprache für die nächste Generation des Backends war, das PyDrone genannt wurde.

Python wurde für diese Arbeit gewählt, weil es eine der besten Sprachen für Naturwissenschaftler ist, also für Leute ohne Informatik-Hintergrund. Viele andere leistungsfähige und ausdrucksstarke Hochsprachen existieren, darunter Perl, Lisp, Scheme, Ruby, CAML und Haskell. Von all diesen ist Python eine der wenigen, die auf Forschung zur Benutzerfreundlichkeit und den Faktoren basiert, die eine Programmiersprache leicht zu erlernen und zu verwenden machen. Doch Python wurde auch entwickelt, um reale Probleme zu lösen, mit denen ein erfahrener Programmierer konfrontiert ist. Das Ergebnis ist eine Sprache, die gut von kleinen Skripten, die von einem Chemiker geschrieben wurden, bis hin zu großen Paketen, die von einem Softwareentwickler geschrieben wurden, skaliert.

Fehlerbehandlung von Python verbessert die Robustheit

Die erste Iteration von PyDrone refaktorierte den bestehenden Perl-Code in geeignetere Funktionen, Klassen und Module, während die Codebasis in Python übersetzt wurde. Das Refactoring des Perl-Codes ohne Umstieg auf Python hätte vergleichbare architektonische Ergebnisse geliefert, aber die explizite Fehlerbehandlung und die stärkere Typenprüfung von Python trugen erheblich zur Verbesserung der Robustheit des Codes bei.

Die aktuelle Version von PyDrone verwendet etwa 20 verschiedene externe Binärdateien und Skripte zur Vorhersage verschiedener molekularer Eigenschaften. Wenn ein externes Programm korrekt funktioniert, ist die Ausgabe leicht in die gewünschten Ergebnisse zu parsen. Diese Programme funktionieren jedoch nicht immer korrekt, sind nicht vollständig dokumentiert, und es ist oft schwierig, alle möglichen Fehlerfälle von außen zu bestimmen. Um dies zu kompensieren, schrieben die PyDrone-Entwickler Tests, um so viele Fehlerfälle wie möglich vorherzusehen, aber es war unmöglich, nach der Bereitstellung zusätzliche unerwartete Fehlerfälle auszuschließen.

Aus Erfahrung mit diesem Problem, zuerst in Perl (Drone) und dann in Python (PyDrone), stellten wir fest, dass Python viele Arten von Fehlern besser abfängt und unerwartete Probleme in einer bereitgestellten Anwendung besser verwaltet. Dies ist ein Ergebnis der Art und Weise, wie die beiden Sprachen die Fehlerbehandlung im Allgemeinen angehen. Zum Beispiel sind die I/O-Routinen von Perl leise und Fehler müssen explizit überprüft werden, meist mit dem "or die"-Idiom. Ein gewissenhafter Programmierer wird diese immer hinzufügen, aber sie nehmen Platz weg, sind leicht zu vergessen und schwer zu testen. Im Gegensatz dazu sind Python-Funktionen laut und lösen bei einem Problem im Code fast immer automatisch eine Ausnahme aus.

Nachdem wir in Python umgeschrieben hatten, dachten wir zunächst, dieses laute Verhalten sei lästig, weil Python ständig Ausnahmen auslöste und abbrach, wo der alte Perl-Code weitergelaufen war. Wir stellten jedoch bald fest, dass fast jede Ausnahme einen zuvor unentdeckten Fehlerfall anzeigte, für den wir neuen Fehlerbehandlungscode hinzufügen mussten. Python half uns, Problemstellen zu finden und verhinderte, dass stille Fehler in unsere Daten gelangten.

Ein Beispiel für einen Fehlerfall, den Python für uns aufgedeckt hat, wurde durch ein externes Prädiktionsprogramm verursacht, das normalerweise einen numerischen Fehlercode zurückgab, in einigen Fällen aber die Zeichenkette "error" zurückgab. In Perl werden Zeichenketten und Zahlen automatisch konvertiert, zum Beispiel die Zeichenkette"123"wird zu der Ganzzahl123. Leider konvertiert Perl auch nicht-numerische Zeichenketten, wie z. B."error", zu0. Infolgedessen behandelte Drone "error" als erfolgreichen Rückgabewert, was zu falschen Ergebnissen führte. Die stärkere Typisierung von Python deckte den Fehler auf, sobald der seltene Fall, der ihn verursachte, ausgeführt wurde.

Eine weitere Möglichkeit, wie Python uns half, unseren Code zu verbessern, war die Einbeziehung eines vollständigen Stack-Tracebacks mit jeder Fehlermeldung. Wir fanden dies sehr nützlich, um die Ursache eines Problems zu verstehen, ohne einen Debugger ausführen oder zusätzliche Code-Instrumentierung hinzufügen zu müssen. Dieses Feature von Python war besonders hilfreich beim Remote-Debugging seltener Fälle. Andrew ist in den Vereinigten Staaten und Pierre in Frankreich. Wenn ein Fehler auftrat, enthielt Pierres E-Mail mit dem Traceback oft genügend Informationen, um das Problem zu lokalisieren und zu beheben.

Hinzufügen leistungsfähiger Erweiterbarkeit mit Python

Die nächste Stufe der PyDrone-Entwicklung war die Verbesserung seiner Erweiterbarkeit. Einige molekulare Eigenschaften hängen von anderen Eigenschaften ab. Beispielsweise hängt die Masse eines Moleküls von seiner Zusammensetzung ab. Der ältere Drone-Code verwaltete diese Abhängigkeiten manuell mit einer Reihe von 'if'-Anweisungen, die angaben, welche Prädiktionsroutinen aufgerufen werden sollten und in welcher Reihenfolge während der Ausführung einer Analyse. Bei diesem Ansatz führte das Hinzufügen neuer Abhängigkeiten bald zu einem kombinatorischen Albtraum.

Um dieses Problem in Python zu lösen, entwickelten wir eine einfache Regelbasis, die wie ein Python-Dictionary funktioniert. Sie enthält einen Daten-Cache und eine Zuordnung von Eigenschaftsnamen zu Prädiktionsfunktionen. Wenn ein angeforderter Eigenschaftsname (der Schlüssel im Dictionary) im Cache vorhanden ist, verwenden wir ihn wieder. Andernfalls finden wir die zugehörige Funktion, rufen sie auf, um den Wert zu berechnen, speichern das Ergebnis im Cache und geben es zurück. Den Funktionen selbst wird eine Referenz auf den Property-Manager übergeben, damit sie rekursiv alle zusätzlich benötigten Abhängigkeiten anfordern können. Um eine neue Vorhersage hinzuzufügen, registrieren wir die neue Funktion in der Funktionstabelle – und lassen die Funktionen selbst die Abhängigkeiten verwalten. Der Cache wird benötigt, da einige Eigenschaften teuer zu berechnen sind oder von vielen anderen Eigenschaften benötigt werden.

Architecture of the Property Manager

Architektur des Property Managers Vergrößern

Die daraus resultierende neue Architektur führte zu einer einfachen, aber tiefgreifenden Veränderung des Projekts. Wir haben jetzt ein einziges System, das alle aktuellen und zukünftigen Vorhersagemethoden aufnehmen kann, das nur das Minimum berechnet, das zur Erzielung der gewünschten Ergebnisse erforderlich ist, und das leicht zu verstehen und zu warten ist. Bevor wir es in Python bauten, hatten mehrere Leute im Unternehmen argumentiert, dass ein solches System überhaupt nicht gebaut werden könne.

Die Vorteile des Python-Typsystems

Die PyDrone-Architektur hätte in vielen Sprachen implementiert werden können, aber Pythons dynamische Typisierung erleichterte den Aufbau unseres Property Managers erheblich. Einige molekulare Eigenschaften sind Zahlen, andere Zeichenketten, Listen und Dictionaries, und wieder andere sind Klasseninstanzen. Eine statisch typisierte Sprache hätte zusätzlichen Aufwand erfordert, um eine Mischung von Rückgabetypen in den Property Manager einzufügen. Selbst Perl, das ebenfalls dynamisch typisiert ist, hätte eine Möglichkeit erfordert, zwischen Referenzen auf ein$scalar, %hashoder@listzu unterscheiden. In Python funktionierte es einfach, und wir konnten die Datentypen der Schlüssel im Property Manager Dictionary ohne zusätzlichen Aufwand mischen. Doch, wie oben beschrieben, bietet Python gleichzeitig eine ausreichende Datenprüfung, um viele Arten von häufigen Typfehler-Mismatches zu finden.

Einer der Faktoren, die unseren Property Manager so erfolgreich machten, war, dass Python es benutzerdefinierten Typen ermöglicht, das Verhalten von integrierten Typen zu emulieren. Unser Property Manager verhält sich sehr ähnlich einer Nachschlagetabelle, die Eigenschaftsnamen auf Werte abbildet, daher haben wir ihn so konzipiert, dass er ein Python-Dictionary emuliert. In Python geschieht dies durch die Implementierung spezifischer spezieller Methoden wie__getitem__(), __setitem__()und so weiter. Durch die Emulation eines Dictionaries würden fast alle anderen Python-Funktionen, die mit einem Dictionary arbeiten, mit unserem Manager funktionieren. Das machte den Code auch einfacher zu verstehen und zu debuggen, da die Syntax und die Verwendung an den Aufrufstellen natürlich zu dem passten, was die Leute erwarten.

Python erleichterte die Implementierung unseres Property Managers auch auf andere Weise. Ein PyDrone-Feature, das von Benutzern angefordert worden war, war die Möglichkeit, eine neue Vorhersage anhand einer Gleichung zu beschreiben, die auf vorhandenen Eigenschaften basiert. Zum Beispiel könnte eine Gleichung so aussehen:

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)

wobei die Variablen Schlüssel im Property Manager sind. Dies war in Python recht einfach zu implementieren, und es wäre schwer, eine Sprache zu finden, die es noch einfacher macht. Pythons mathematische Ausdrücke sind fast identisch mit der Standardform, die in den Wissenschaften verwendet wird, sodass wir Pythons "eval"-Anweisung verwenden konnten, um die benutzdefinierten Ausdrücke zu parsen und auszuwerten. Da unser Property Manager wie ein Python-Dictionary funktioniert, konnte er (zumindest theoretisch) direkt an die eval-Anweisung als lokales Dictionary für die Variablensuche während der Auswertung der Ausdrücke übergeben werden.

Es stellte sich heraus, dass dieeval()-Implementierung in Python aus Performancegründen nur integrierte Dictionary-Typen und keine emulierten Mapping-Typen akzeptiert, sodass wir einige zusätzliche Tricks anwenden mussten, um unser On-Demand-Abhängigkeitssystem mit Gleichungen zum Laufen zu bringen. Nichtsdestotrotz war die gesamte Implementierung recht einfach.

Ergebnisse

PyDrone benötigte etwa 3 Monate Entwicklungszeit, weitere 3 Monate für QA und 3 Wochen für die Dokumentation, um etwa 5.600 Zeilen fertigen Python-Codes zu produzieren.

Insgesamt war PyDrone ein wunderbarer Erfolg für AstraZeneca. Durch die Verwendung von Python konnten wir schnell und einfach ein großartiges Werkzeug entwickeln, das sowohl sehr einfach zu bedienen ist als auch gut an neue Vorhersagemethoden angepasst werden kann.

Das größte Problem, das wir mit Python hatten, ist, dass relativ wenige Leute bei AstraZeneca es für die Entwicklung nutzen. Die IT-Abteilung bevorzugt entweder Perl (Systemleute) oder Java (Architekturleute), daher erhalten wir gelegentlich Anfragen, Teile des Projekts in einer dieser Sprachen neu zu schreiben. Selbst so haben wir festgestellt, dass Entwickler daran interessiert sind, Python zu lernen, insbesondere wenn sie Vergleiche der Entwicklungszeit und des Aufwands, der resultierenden Code-Größe und anderer Metriken sehen.

Über die Autoren

Scott Boyer ist ein Principal Scientist in der Sektion Enabling Science and Technology von AstraZeneca Discovery R&D, Mölndal, Schweden. Scott promovierte an der University of Colorado, Boulder, und arbeitete sowohl bei Pfizer als auch bei AstraZeneca in experimenteller Massenspektrometrie und NMR im Zusammenhang mit der Festlegung optimaler 'Drug-Like Properties'. Vor etwa vier Jahren wechselte er zur 'dunklen Seite' der Computerchemie und leitet nun das interne Projekt, um mehr Modellierungswerkzeuge für Labormitarbeiter an allen 10 Forschungsstandorten von AstraZeneca bereitzustellen.

Andrew Dalke ist Gründer von Dalke Scientific Software, LLC, einem Softwareberatungs- und Auftragsentwicklungsunternehmen mit Sitz in Santa Fe, New Mexico, USA. Andrew entwickelt seit 1992 Software für computergestützte Chemie und Biologie. Sein Hauptaugenmerk liegt auf der Kombination von Usability-Design und Software-Engineering, um Software-Tools zu entwickeln, die Wissenschaftler sowohl nutzen als auch genießen. Kein Wunder, dass er Python so sehr mag.

Pierre Bruneau ist ein Principal Scientist im Bereich Cancer and Infection Research bei AstraZeneca Discovery, Reims, Frankreich. Nach seinem Chemiestudium an der Ecole Nationale Supérieure de Chimie de Strasbourg trat er zunächst Organon R&D und dann AstraZeneca (ehemals ICI Pharma und dann Zeneca) in Reims, Frankreich, bei. Nach mehreren Jahren als medizinischer Chemiker leitet Pierre nun die lokale physikalisch-chemische und Computer-Gruppe des französischen Labors, während er ein Interesse an der Entwicklung von Methoden und Werkzeugen zur Vorhersage physikochemischer Eigenschaften und zur Festlegung von Struktur-Wirkungs-Beziehungen potenzieller Arzneimittelmoleküle hat.