【化合物スクリーニング】RDkitを使った化合物のフィルタリング【in silico創薬】

この記事は化合物ライブラリにおいて、ある程度薬物になりそうな化合物のフィルタリングを行うやり方を紹介します。具体的にはLipinskiのRule of FiveやPAINSなどのフィルターを活用することで、開発候補として適切な化合物を選別することができます。環境構築から丁寧に書いているので、ぜひ参考にしてください。

動作検証済み環境

Mac M1, Sequoia 15.3, メモリ 16GB

目次


環境構築

まず、RDKitを使用するための仮想環境を作成し、必要なライブラリをインストールします。

1. Minicondaのインストール(未インストールの場合)

RDKitはcondaを用いてインストールするのが便利です。そのため、まずMinicondaをインストールしてください。

(下はintelチップのものを使っています。)

(intelチップの用)
curl -O <https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh>
bash Miniconda3-latest-MacOSX-x86_64.sh
(M1/M2/M3 Mac用 ARM64版)
curl -O <https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh>
bash Miniconda3-latest-MacOSX-arm64.sh
source ~/.zshrc
conda --version # condaのバージョンが表示されればインストール成功
  1. curl -O <URL>
    • curl コマンドは、指定したURLからファイルをダウンロードするためのツールです。
    • O オプションは、ダウンロードしたファイルをそのままの名前で保存することを意味します。
    • 例えば、Intel Macでは Miniconda3-latest-MacOSX-x86_64.sh、Apple Silicon Macでは Miniconda3-latest-MacOSX-arm64.sh という名前のファイルが保存されます。
  2. bash Miniconda3-latest-MacOSX-<アーキテクチャ>.sh
    • bash コマンドでダウンロードしたインストーラーを実行します。
    • インストール時にいくつかの設定が求められます。基本的にはyesまたはデフォルトの設定で進めて問題ありません。
  3. source ~/.zshrc
    • source コマンドは、指定した設定ファイル(ここでは ~/.zshrc)を再読み込みするためのものです。
    • Minicondaのインストールが完了すると、~/.zshrcconda コマンドのパスが追加されます。
    • これを反映しないと、ターミナルを再起動するまで conda コマンドが使えません。
  4. conda --version
    • conda --version を実行すると、conda 23.1.0 のようにバージョン番号が表示されます。
    • これが表示されれば、Minicondaが正常にインストールされたことを意味します。

2. 仮想環境の作成と有効化

以下のコマンドを実行して、RDKit専用の仮想環境を作成し、有効化します。

conda create -c conda-forge -n in_silico rdkit

このコマンドの意味:

  1. conda create
    • 新しい仮想環境を作成するためのコマンドです。
  2. c conda-forge
    • c は「チャンネル(channel)」を指定するオプションです。
    • conda-forge はコミュニティが管理しているリポジトリで、RDKitの最新バージョンが提供されています。
  3. n in_silico
    • n オプションは、新しく作成する環境の名前を指定します。
    • ここでは in_silico という名前の仮想環境を作成します。
  4. rdkit
    • RDKitをこの環境にインストールします。

仮想環境を有効化するには、以下を実行します。

conda activate in_silico

in_silicoという名前の仮想環境が有効化され、その環境内でRDKitが使用可能になります。

(終了したら、conda deactivateを押してください。再度行いたい時はconda activate in_silicoをするとできます)

3. Cursorを用いたJupyter環境の用意

ここでは最近流行りのAI搭載のEditorを使って、コードを実行していくことにします。

こちらからCursorをインストールしてください。

ライブラリを保存した、ディレクトリを開いてください。

左の方にあるExtensionsのマークからJupyterをインストールしてください。

続いて、右側の箇所(画像だとbaseと書いてあるところ)を押し、環境を設定します。

Select Another Kernel…→Python Environments…→Filteringをクリックし、先ほど設定した環境を設定します。

RDkitを用いた化合物のフィルタリング

全コードはこちら。以下のように一つ一つ書き、Shift + Enterで一つ一つ実行していけば、できます。

今回フィルタリングするライブラリは以下の記事で紹介されているselleckchem bioactive library I になります。化合物数は9576種類です。

化合物ライブラリまとめ【in silico創薬】【in silicoスクリーニング】 – LabCode

#libraryのインストール
from rdkit import Chem
from rdkit.Chem import Descriptors, Crippen
from rdkit.Chem.FilterCatalog import FilterCatalog, FilterCatalogParams
def is_drug_like(mol): """ リピンスキーのRule of Fiveに基づいて、分子がdrug-likeか判定する関数 ・分子量 (MW) ≤ 500 ・LogP ≤ 5 ・水素結合供与体 (H-bond donors) ≤ 5 ・水素結合受容体 (H-bond acceptors) ≤ 10 """ mw = Descriptors.MolWt(mol) logP = Crippen.MolLogP(mol) h_donors = Descriptors.NumHDonors(mol) h_acceptors = Descriptors.NumHAcceptors(mol) if mw > 500: return False if logP > 5: return False if h_donors > 5: return False if h_acceptors > 10: return False return True
# 利用可能なフィルターの辞書
available_filters = { 'PAINS_A': FilterCatalogParams.FilterCatalogs.PAINS_A, 'PAINS_B': FilterCatalogParams.FilterCatalogs.PAINS_B, 'PAINS_C': FilterCatalogParams.FilterCatalogs.PAINS_C, 'PAINS': FilterCatalogParams.FilterCatalogs.PAINS, 'BRENK': FilterCatalogParams.FilterCatalogs.BRENK, 'NIH': FilterCatalogParams.FilterCatalogs.NIH, 'ZINC': FilterCatalogParams.FilterCatalogs.ZINC, 'ALL': FilterCatalogParams.FilterCatalogs.ALL
}
def setup_custom_filter(selected_keys): """ 指定されたフィルターキーに基づいてFilterCatalogを作成する関数 Parameters: selected_keys (list of str): 使用するフィルターのキーリスト(例: ['PAINS_A', 'BRENK', 'NIH']) Returns: FilterCatalog: 選択したフィルターをまとめたカタログ """ params = FilterCatalogParams() for key in selected_keys: if key in available_filters: params.AddCatalog(available_filters[key]) return FilterCatalog(params) def passes_filters(mol, filter_catalog): """ 指定したフィルターにヒットしなければTrueを返す HasMatchがTrueの場合、いずれかのフィルターにマッチしているためFalse """ return not filter_catalog.HasMatch(mol) def main(): # 入力SDFファイルのパス(実際のファイル名に合わせて変更してください) input_sdf = "20250211-L1700-Bioactive-Compound-Library-I.SDF" supplier = Chem.SDMolSupplier(input_sdf) # 使用するフィルターキーを選択(ここでは例として、PAINS_A, PAINS_B, PAINS_C, BRENK, NIHを選択) selected_filters = ['PAINS_A', 'PAINS_B', 'PAINS_C'] filter_catalog = setup_custom_filter(selected_filters) # フィルタリング結果を格納するリスト filtered_mols = [] # 各分子について、Rule of Fiveと選択したフィルターを適用 for mol in supplier: if mol is None: continue if is_drug_like(mol) and passes_filters(mol, filter_catalog): filtered_mols.append(mol) print("Rule of Five, および選択したフィルターを通過した化合物の数:", len(filtered_mols)) # フィルタリング結果をSDFファイルに出力 output_sdf = "filtered_compounds.sdf" writer = Chem.SDWriter(output_sdf) for mol in filtered_mols: writer.write(mol) writer.close() print(f"SDFファイルとして {output_sdf} に出力しました。") if __name__ == "__main__": main()

各詳細の解説は以下になります。

1. ライブラリのインポート

仮想環境が有効化された状態で、以下のコードを実行してライブラリをインポートできるか確認してください。

#libraryのインストール
from rdkit import Chem
from rdkit.Chem import Descriptors, Crippen
from rdkit.Chem.FilterCatalog import FilterCatalog, FilterCatalogParams

from rdkit import Chem

  • RDKitの基本的な化学構造を扱うためのモジュールをインポートします。
  • 例えば、分子構造の読み込みや変換、スマイルズ(SMILES)記法のパースなどができます。
mol = Chem.MolFromSmiles("CCO") # エタノールのSMILESを分子オブジェクトに変換
print(mol)

from rdkit.Chem import Descriptors

  • 分子の物性を計算するためのモジュールです。
  • 例: 分子量、LogP(水溶性/脂溶性指標)、水素結合供与体数 など
mol_weight = Descriptors.MolWt(mol) # 分子量
print(f"分子量: {mol_weight}")

from rdkit.Chem import Crippen

  • LogP(脂溶性指標)や極性表面積(TPSA) の計算が可能です。
logp = Crippen.MolLogP(mol) # LogP値の計算
print(f"LogP: {logp}")

from rdkit.Chem.FilterCatalog import FilterCatalog, FilterCatalogParams

  • 化学的なフィルタリング(有害な分子や毒性のある分子の除外)に使用するモジュールです。
  • RDKitには「PAINSフィルター」などの一般的なルールが組み込まれています。
params = FilterCatalogParams()
params.AddCatalog(FilterCatalogParams.FilterCatalogs.PAINS) # PAINSフィルターを適用
catalog = FilterCatalog(params)
if catalog.HasMatch(mol): print("この分子はPAINSフィルターに引っかかりました。")
else: print("この分子はPAINSフィルターを通過しました。")

2. LipinskiのRule of Fiveを用いたスクリーニング

LipinskiのRule of Fiveに基づき、以下の基準を満たす分子をdrug-likeな化合物と判定します。

  • 分子量(MW) ≤ 500
  • LogP ≤ 5
  • 水素結合供与体 ≤ 5
  • 水素結合受容体 ≤ 10

以下の関数を使用して、分子がこの基準を満たしているかを判定します。

def is_drug_like(mol): """ リピンスキーのRule of Fiveに基づいて、分子がdrug-likeか判定する関数 ・分子量 (MW) ≤ 500 ・LogP ≤ 5 ・水素結合供与体 (H-bond donors) ≤ 5 ・水素結合受容体 (H-bond acceptors) ≤ 10 """ mw = Descriptors.MolWt(mol) logP = Crippen.MolLogP(mol) h_donors = Descriptors.NumHDonors(mol) h_acceptors = Descriptors.NumHAcceptors(mol) if mw > 500: return False if logP > 5: return False if h_donors > 5: return False if h_acceptors > 10: return False return True

コード解説

def is_drug_like(mol):
  • 関数 is_drug_like(mol) の定義
  • molRDKitMol オブジェクト(化合物の構造情報を持つ)
mw = Descriptors.MolWt(mol)
  • Descriptors.MolWt(mol) は分子の**分子量(MW)**を計算
logP = Crippen.MolLogP(mol)
  • Crippen.MolLogP(mol) は分子の**LogP(疎水性)**を計算
h_donors = Descriptors.NumHDonors(mol)
h_acceptors = Descriptors.NumHAcceptors(mol)
  • NumHDonors(mol): 水素結合供与体の数
  • NumHAcceptors(mol): 水素結合受容体の数
if mw > 500: return False
if logP > 5: return False
if h_donors > 5: return False
if h_acceptors > 10: return False
  • 4つのルールのいずれかを満たさない場合 False を返す(=ドラッグライクでない)
return True
  • すべての条件を満たしていれば True(ドラッグライク)を返す

使用例

from rdkit import Chem
from rdkit.Chem import Descriptors, Crippen
smiles = "CCOc1ccc2nc(S(N)(=O)=O)sc2c1" # ある化合物のSMILES表記
mol = Chem.MolFromSmiles(smiles)
print(is_drug_like(mol)) # True or False
  • Chem.MolFromSmiles(smiles): SMILES 文字列から Mol オブジェクトを生成
  • is_drug_like(mol): ドラッグライクかどうか判定

3. PAINSフィルターを用いたフィルタリング

PAINSフィルターは、非特異的な結合をする可能性が高い化合物を除外するために使用されます。 RDKitでは、以下のようなフィルターを適用することができます。

# 利用可能なフィルターの辞書
available_filters = { 'PAINS_A': FilterCatalogParams.FilterCatalogs.PAINS_A, 'PAINS_B': FilterCatalogParams.FilterCatalogs.PAINS_B, 'PAINS_C': FilterCatalogParams.FilterCatalogs.PAINS_C, 'PAINS': FilterCatalogParams.FilterCatalogs.PAINS, 'BRENK': FilterCatalogParams.FilterCatalogs.BRENK, 'NIH': FilterCatalogParams.FilterCatalogs.NIH, 'ZINC': FilterCatalogParams.FilterCatalogs.ZINC, 'ALL': FilterCatalogParams.FilterCatalogs.ALL
}
def setup_custom_filter(selected_keys): """ 指定されたフィルターキーに基づいてFilterCatalogを作成する関数 Parameters: selected_keys (list of str): 使用するフィルターのキーリスト(例: ['PAINS_A', 'BRENK', 'NIH']) Returns: FilterCatalog: 選択したフィルターをまとめたカタログ """ params = FilterCatalogParams() for key in selected_keys: if key in available_filters: params.AddCatalog(available_filters[key]) return FilterCatalog(params)
def passes_filters(mol, filter_catalog): """ 指定したフィルターにヒットしなければTrueを返す HasMatchがTrueの場合、いずれかのフィルターにマッチしているためFalse """ return not filter_catalog.HasMatch(mol)

このコードは、RDKitのフィルターカタログ(FilterCatalog)を設定 する関数を定義しています。特に、PAINSフィルターやBRENKフィルターなどのスクリーニングルール を活用して、創薬候補の化合物から望ましくない構造を持つものを除外 するためのものです。

コードの詳細解説

フィルターの種類を辞書で定義

available_filters = { 'PAINS_A': FilterCatalogParams.FilterCatalogs.PAINS_A, 'PAINS_B': FilterCatalogParams.FilterCatalogs.PAINS_B, 'PAINS_C': FilterCatalogParams.FilterCatalogs.PAINS_C, 'PAINS': FilterCatalogParams.FilterCatalogs.PAINS, 'BRENK': FilterCatalogParams.FilterCatalogs.BRENK, 'NIH': FilterCatalogParams.FilterCatalogs.NIH, 'ZINC': FilterCatalogParams.FilterCatalogs.ZINC, 'ALL': FilterCatalogParams.FilterCatalogs.ALL
}

この辞書 available_filters には、各種フィルターの種類が定義されています。

フィルターには以下のようなものがあります:

  • PAINS(Pan-Assay Interference Compounds)
    • PAINS_A, PAINS_B, PAINS_C: サブカテゴリー
    • PAINS: すべてのPAINSフィルター
    • 目的: 創薬ターゲットを誤ってヒットさせる可能性のある化合物を除外
  • BRENK
    • 医薬品としての開発に適さない「毒性を持つ可能性のある構造」を持つ化合物を除外
  • NIH
    • NIHで定義された望ましくない化合物のフィルター
  • ZINC
    • ZINCデータベースに基づく化合物フィルター
  • ALL
    • すべてのフィルターを適用(最大限の除外)

フィルターカタログの作成

def setup_custom_filter(selected_keys): """ 指定されたフィルターキーに基づいてFilterCatalogを作成する関数 Parameters: selected_keys (list of str): 使用するフィルターのキーリスト(例: ['PAINS_A', 'BRENK', 'NIH']) Returns: FilterCatalog: 選択したフィルターをまとめたカタログ """ params = FilterCatalogParams() # フィルターカタログのパラメータを作成 for key in selected_keys: if key in available_filters: params.AddCatalog(available_filters[key]) # 指定されたフィルターを追加 return FilterCatalog(params) # 作成したフィルターカタログを返す

この関数では、ユーザーが指定したフィルター(例: ['PAINS_A', 'BRENK', 'NIH'])を適用 した FilterCatalog を作成します。


使用例

以下のように setup_custom_filter を使って、PAINS_A, BRENK, NIH の3種類のフィルターを適用した FilterCatalog を作成できます。

from rdkit.Chem.FilterCatalog import FilterCatalog, FilterCatalogParams
# 3種類のフィルターを適用
custom_filter = setup_custom_filter(['PAINS_A', 'BRENK', 'NIH'])
# SMILES 形式の化合物
smiles = "CCOc1ccc2nc(S(N)(=O)=O)sc2c1" # ある化合物
mol = Chem.MolFromSmiles(smiles)
# フィルターを適用して判定
if custom_filter.HasMatch(mol): print("この化合物はフィルターに引っかかりました!")
else: print("この化合物は問題なし")

この関数を使用して、指定したPAINSフィルターを適用できます。

def passes_filters(mol, filter_catalog): """ 指定したフィルターにヒットしなければTrueを返す HasMatchがTrueの場合、いずれかのフィルターにマッチしているためFalse """ return not filter_catalog.HasMatch(mol)
  • filter_catalog.HasMatch(mol)
    • 分子がフィルターにマッチしているかどうか を判定
    • Trueフィルターに引っかかった(望ましくない化合物)
    • False問題なし
  • not filter_catalog.HasMatch(mol)
    • HasMatch(mol)False(問題なし)の場合、 True を返す

使用例

from rdkit import Chem
from rdkit.Chem.FilterCatalog import FilterCatalog, FilterCatalogParams
# カスタムフィルターを作成(PAINS_A, BRENK, NIH フィルターを適用)
filter_catalog = setup_custom_filter(['PAINS_A', 'BRENK', 'NIH'])
# 化合物のSMILES
smiles = "CCOc1ccc2nc(S(N)(=O)=O)sc2c1" # ある化合物
mol = Chem.MolFromSmiles(smiles)
# フィルター通過チェック
if passes_filters(mol, filter_catalog): print("この化合物はフィルターを通過しました!(使用可能)")
else: print("この化合物はフィルターに引っかかりました!(除外)")

4. SDFファイルからのフィルタリング

以下のコードを用いて、SDFファイルに含まれる化合物をLipinskiのRule of FiveおよびPAINSフィルターでスクリーニングし、合格した化合物のみを保存します。

def main(): # 入力SDFファイルのパス(実際のファイル名に合わせて変更してください) input_sdf = "20250211-L1700-Bioactive-Compound-Library-I.SDF" supplier = Chem.SDMolSupplier(input_sdf) # 使用するフィルターキーを選択(ここでは例として、PAINS_A, PAINS_B, PAINS_C, BRENK, NIHを選択) selected_filters = ['PAINS_A', 'PAINS_B', 'PAINS_C'] filter_catalog = setup_custom_filter(selected_filters) # フィルタリング結果を格納するリスト filtered_mols = [] # 各分子について、Rule of Fiveと選択したフィルターを適用 for mol in supplier: if mol is None: continue if is_drug_like(mol) and passes_filters(mol, filter_catalog): filtered_mols.append(mol) print("Rule of Five, および選択したフィルターを通過した化合物の数:", len(filtered_mols)) # フィルタリング結果をSDFファイルに出力 output_sdf = "filtered_compounds.sdf" writer = Chem.SDWriter(output_sdf) for mol in filtered_mols: writer.write(mol) writer.close() print(f"SDFファイルとして {output_sdf} に出力しました。")
if __name__ == "__main__": main()

コードの詳細解説

1. メイン関数 main()

def main():

スクリプトのメイン処理を行う関数です。


2. SDFファイルから分子データを読み込む

input_sdf = "20250211-L1700-Bioactive-Compound-Library-I.SDF"
supplier = Chem.SDMolSupplier(input_sdf)
  • Chem.SDMolSupplier(input_sdf) を使って SDFファイル から化合物をロード
  • supplier はリストのように扱え、分子を1つずつ取り出せる

SDF(Structure Data File)とは?

  • 化合物の構造情報を格納するファイル形式
  • RDKitで 大規模な化合物ライブラリを処理 する際によく使われる

3. 適用するフィルターを設定

selected_filters = ['PAINS_A', 'PAINS_B', 'PAINS_C']
filter_catalog = setup_custom_filter(selected_filters)
  • selected_filters に適用する フィルター をリストで指定
  • setup_custom_filter(selected_filters)フィルターカタログ を作成

PAINSフィルターとは?

  • 「創薬ターゲットを誤ってヒットさせる可能性のある化合物」 を排除するフィルター

4. 各化合物について、フィルターを適用

filtered_mols = []
for mol in supplier: if mol is None: continue if is_drug_like(mol) and passes_filters(mol, filter_catalog): filtered_mols.append(mol)
  • 空のリスト filtered_mols を用意
  • supplier から 1つずつ化合物を取り出してフィルタリング
  • is_drug_like(mol)Rule of Five を適用
  • passes_filters(mol, filter_catalog)問題のある化合物を除外
  • 両方をクリアした化合物のみ filtered_mols に追加
  • mol is None のチェックが重要!
    • SDFファイルには 無効な分子データ が含まれることがあるため、 None をスキップ

5. フィルタリング後の化合物数を表示

print("Rule of Five, および選択したフィルターを通過した化合物の数:", len(filtered_mols))
  • 何個の化合物がフィルターを通過したか を表示

5. 結果をSDFファイルに出力

output_sdf = "filtered_compounds.sdf"
writer = Chem.SDWriter(output_sdf)
for mol in filtered_mols: writer.write(mol)
writer.close()
print(f"SDFファイルとして {output_sdf} に出力しました。")
  • Chem.SDWriter(output_sdf) を使って 新しいSDFファイルを作成
  • filtered_mols に入っている 合格した化合物を1つずつ書き込み
  • 最後に writer.close() でファイルを閉じる

6. スクリプトを実行

if __name__ == "__main__": main()
  • Pythonスクリプトとして直接実行された場合のみ main() を実行
  • モジュールとしてインポートされた場合には実行されない(再利用しやすい)

出力結果

SDFファイルの中の化合物の状況で、いくつかエラーが出てきますが、以下のような出力が出てきます。

Rule of Five, および選択したフィルターを通過した化合物の数: 6489
SDFファイルとして filtered_compounds.sdf に出力しました。

filtered_compounds.sdfが現在のディレクトリに生成していると思います。

(他のファイルは気にしなくて大丈夫です。)

9576種類の中から6489種類残りましたので、約3000化合物がフィルタリングで外れたことになりますね。


まとめ


本記事では、RDKitを用いて化合物のフィルタリングを行う方法を解説しました。

本記事を参考にすることで、より効率的に化合物のスクリーニングを行うことが可能になります。RDKitを活用して、より良い創薬候補を見つけてみてください!


参考文献



コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です