【ChEMBL/STRING】化合物の標的Pathwayを取得【正確確率検定】

1細胞マルチオーム法

$N_c$種類の化合物と$N_p$種類のPathwayがあるとします。

このとき、「化合物$i$ ($i=1, …, N_c$)の標的タンパク群」と「Pathway$j$ ($j=1, …, N_p$)を構成するタンパク群」の重なり度合いを、Fisherの正確確率検定によって$p$値として評価することができます。

具体的には以下のような表が得られます。

Pathway $1$Pathway $2$Pathway $j$Pathway $N_p$
化合物 $1$$p_{11}$$p_{12}$$p_{1j}$$p_{1N_{p}}$
化合物 $2$$p_{21}$$p_{22}$$p_{2j}$$p_{2N_{p}}$
化合物 $i$$p_{i1}$$p_{i2}$$p_{ij}$$p_{iN_{p}}$
化合物 $N_c$$p_{N_{c}1}$$p_{N_{c}2}$$p_{N_{c}j}$$p_{N_{c}N_{p}}$

上記のテーブルの行で定義される横ベクトルを「化合物の標的Pathway」とします。

そこで本記事では上記のテーブルを作成する手順を説明します。

0. はじめに

本記事は、以下の記事の続きになります。

1. 化合物の標的タンパクを取得

以下の記事に従い、化合物のInChIKeyから標的タンパクのリスト(シンボル表記)を得る辞書(ink_syms)を作成します。

あるいは以下のようにpickleでロードします。

with open(f'{TEMP_DIR}/pathwayTerm_to_symbols.pkl', 'rb') as tf:
    ptm_syms = pickle.load(tf)

2. Pathwayを構成するタンパクを取得

以下の記事に従い、PathwayのIDからPathwayに含まれるのタンパクのリスト(シンボル表記)を得る辞書(ptm_syms)を作成します。

あるいは以下のようにpickleでロードします。

with open(f'{TEMP_DIR}/pathwayTerm_to_symbols.pkl', 'rb') as tf:
    ptm_syms = pickle.load(tf)

3. Fisherの正確確率検定

冒頭でも示した以下の表について、$p_{ij}$を計算する方法を説明します。

Pathway $1$Pathway $2$Pathway $j$Pathway $N_p$
化合物 $1$$p_{11}$$p_{12}$$p_{1j}$$p_{1N_{p}}$
化合物 $2$$p_{21}$$p_{22}$$p_{2j}$$p_{2N_{p}}$
化合物 $i$$p_{i1}$$p_{i2}$$p_{ij}$$p_{iN_{p}}$
化合物 $N_c$$p_{N_{c}1}$$p_{N_{c}2}$$p_{N_{c}j}$$p_{N_{c}N_{p}}$

まずは化合物 $i$ とPathway $j$ について以下のような分割表を作成します。

タンパク ($N$)化合物 $i$ に合計
含まれない含まれる
Pathway $j$ に含まれる$a$$b$$a + b$
含まれない$c$$d$$c + d$
合計$a + c$$b + d$$a + b + c + d = N$

合計部分を固定した場合、上記のような表が得られる確率は超幾何分布に従います(詳しくはこちらの記事)。

具体的には以下のようにして$p_{ij}$を計算できます。

$$p_{ij} = \frac{{}_{a+c}C_a \times {}_{b+d}C_b}{{}_{n}C_{a+b}}$$

4. 実装

まずは全タンパクの数($=N$)を計算します。pathways_proteinsこちらの記事で、compounds_proteinsこちらの記事で作成した変数です。

# n_proteins
proteins_string_chembl = list(set(pathways_proteins) | set(compounds_proteins))
n_proteins = len(proteins_string_chembl)
print(f'# of unique proteins found in either string dataset or chembl dataset: {n_proteins}')
# of unique proteins found in either string dataset or chembl dataset: 24214

次に分割表を作成する関数を定義します。引数に渡す値は以下です。

  • target_proteins:化合物$i$の標的タンパクのシンボル表記のリスト(ink_syms[i])
  • proteins_in_pathway:Pathway$j$を構成するタンパクのシンボル表記のリスト(ptm_syms[j])
  • n_proteins:先ほど計算したn_proteins
# library
import pandas as pd

# contingency table: each compound x each pathway
def make_contingency_table(
    target_proteins,
    proteins_in_pathway,
    n_proteins
):
    _b = set(target_proteins) & set(proteins_in_pathway)
    _a = set(proteins_in_pathway) - _b
    _d = set(target_proteins) - _b
    
    a, b, d = len(list(_a)), len(list(_b)), len(list(_d))
    c = n_proteins - (a + b + d)
    
    df_table = pd.DataFrame([[a, b], [c, d]])
    df_table.columns = ['~is_target', 'is_target']
    df_table.index = ['isin_pathway', '~isin_pathway']
    df_table = df_table.T
    
    return df_table

続いて、上記で作成した分割表を作成する関数(make_contingency_table)の返り値を引数として、Fisherの正確確率検定による$p$値を返す関数を作成します。

# library
from scipy.stats import fisher_exact

# fisher's exact test
def calc_p(table):
    odds_ratio, p = fisher_exact(table, alternative='less')
    return p

最後に、化合物のInChIKeyのリストとPathwayのID(term)をリストを引数とし、化合物とPathwayの全組合せのパターンについて上記のcalc_p関数を実施する関数enrichment_analysisを作成します。

なお、InChIKeyから標的タンパクのシンボル表記を得るためにink_symsを、Pathway ID (term)からPathwayを構成するタンパクのシンボル表記を得るためにptm_symsも引数として渡します。加えて、正確確率検定に必要なn_proteinsも引数に加えます。

# make table & tests for all inputs
def enrichment_analysis(
    inkList, ptmList, n_proteins,
    ink_syms, ptm_syms
):
    pvals = []
    
    for i, ik in enumerate(inkList):
        pvals.append([])

        for pt in ptmList:
            table = make_contingency_table(ink_syms[ik], ptm_syms[pt], n_proteins)
            pvals[-1].append(calc_p(table))

    return pvals

ただし実際は以下に留意して

  1. 適当な間隔で進捗と計算時間を標準出力
  2. 適当な間隔で結果を保存する

以下のようにした方が良いかもしれません。引数のrep_intervalは間隔に関する値です。

# library
import datetime
import pickle
import time
import os


# const
TEMP_DIR = 'temp'


# 結果の保存先のディレクトリ名に用いるタイムスタンプ出力関数
def now():
    return str(datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S'))

# make table & tests for all inputs
def enrichment_analysis(
    inkList, ptmList, n_proteins,
    ink_syms, ptm_syms,
    rep_interval=50
):
  	# 保存先の作成
	no = now()
    os.makedirs(f'{TEMP_DIR}/pvals/{no}/{len(inkList)}', exist_ok=True)
    
    # 計算時間測定用
    st0 = time.time()
    st = time.time()
    
    # enrichment analysis
    pvals = []    
    for i, ik in enumerate(inkList):
        pvals.append([])

        for pt in ptmList:
            table = make_contingency_table(ink_syms[ik], ptm_syms[pt], n_proteins)
            pvals[-1].append(calc_p(table))

        # save & stdout
        if (i + 1) % rep_interval == 0:
            # save temp array
            with open(f"{TEMP_DIR}/pvals/{len(inkList)}/pvals.{i + 1}.pkl", "wb") as tf:
                pickle.dump(pvals[(i + 1) - rep_interval:(i + 1)], tf)
            
            # stdout (time)
            print(f'{i + 1} / {len(inkList)}: Elapsed time was {time.time() - st:.1f} sec.')
            st = time.time()
    
    # save results
    with open(f"{TEMP_DIR}/pvals/{len(inkList)}/pvals.{i + 1}.pkl", "wb") as tf:
        pickle.dump(pvals[len(pvals) - (len(pvals) % rep_interval):], tf)        

    # stdout (time)
    print(f'Finished: {time.time() - st0:.1f} sec.')
    
    return pvals

5. Pathwayベクトルの算出

前節で定義した関数を用いて、冒頭の表に相当する結果を作成します。

# ChEMBLから取得した化合物のInChIKeyリスト
inks = list(ink_syms.keys())

# STRINGから取得したpathwayのterm(ID)のリスト
ptms = [pt for pt in ptm_syms.keys() if 3 <= len(ptm_syms[pt])]

# enrichment analysis
pvals = enrichment_analysis(
    inks, ptms, n_proteins,
    ink_syms, ptm_syms,
    rep_interval=100
)

6. Pathwayスコアベクトルの算出

前節で計算したp値のベクトルをそのまま使用することは少なく、実際は$-log_{10}$をとった「スコア」を利用します。

スコアの計算は以下のように実施します。

# library
import numpy as np

# dataframe
df_pvals = pd.DataFrame(pvals)
df_pvals.index = inks
df_pvals.columns = ptms

# score
df_pvals = df_pvals.drop_duplicates()
df_score = df_pvals.map(lambda x: -np.log10(x))

# save
no = now()
os.makedirs(f'{TEMP_DIR}/scores/{no}/df_score', exist_ok=True)
with open(f'{TEMP_DIR}/scores/{no}/df_score.pkl', 'wb') as tf:
    pickle.dump(df_score, tf)

7. まとめ

本記事ではChEMBLの標的タンパクデータとSTRINGのPathwayデータを利用し、化合物の標的Pathwayをスコアベクトルの形で算出しました。

コメント