細胞種推定のための機械学習入門

若年組織と老化組織の違いとして、「細胞種比率の違い」があります。例えば、老化によって免疫細胞の割合が増減していたりすることがあります。

このような、細胞種の割合を調べるためには、当然ですが全てのデータで細胞種を同定しておく必要があります。データごとの細胞種が分かれば、あとはこれらの細胞数を集計することで、細胞種比率を算出することができます。


しかし、現状のRNA-Seq解析(細胞のmRNA全量を調べる解析のことです)では、解析している細胞の種類を特定することができません。そもそも、未発見の細胞が未だ多いこともあるため、100%の精度で細胞種を決定するのは不可能だと考えた方がいいでしょう。


そこで、これまでに様々な細胞種「推定」方法が開発されてきました。本記事では、これらの細胞種推定方法のうち、「深層学習」を活用したものを紹介します


機械学習とは?


機械学習とは、データを入力してコンピュータにパターンを認識させることをいいます。


機械学習の「機械」というのは、一般的にパソコンなどのコンピュータを指します。機械学習というのはパソコンに「データのパターン」を学習させる行為のことをいいます。

例えば、パソコンに30年分の気象情報データを入力することで、大気圧や雲行きがどうなったら明日の天気は雨になりやすいとか、そういう「データの傾向」をパソコンが学習します。

学習が完了したパソコンは、新たに大気圧と雲行きデータだけを渡されても、次の日の天気が予測できるようになります。このように、何かの予測を達成するためにデータのパターンを認識させることを機械学習というわけです


機械学習の一つに「教師あり学習」があります。教師あり学習では、正解が分かっているデータを事前に学習させることで、予測のためのモデルを作成します。学習済みのモデルは、次に正解が分かっていないデータが渡されても、その正解を予測してくれます。先ほどの例は、まさに教師あり学習そのものでした。


対比するものとして、「教師なし学習」が存在します。こちらは、類似度などを使ってデータのグループ化を行い、次に新たなデータが渡されたときは、既存の類似データが属するグループに割り当てを行う方法です。

例えば、国語・数学・理科・社会の点数からその生徒が理系か文系かを推定する問題があるとします。教師あり学習では、生徒ごとに理系か文系かが判明している学習用データが与えられますが、教師なし学習では生徒が理系か文系かは一切分かりません。そこで、点数によってグループ分けを行い、数学と理科の点数が高いグループを理系と定義する、ということをします。こうすることで、新たな生徒の成績データが渡されたときに、数学と理科の点数が高ければその生徒は理系であると推定することができます。

教師なし学習の良いところは、理系か文系かという「正解」を用意しなくてよいことです。先ほども述べたように、細胞種を100%正確に決定するのは不可能なので、「正解」が分からない今回のケースでは有用です。

一方で、「どのグループに属するか微妙なデータ」を調べるのは難しいです。グループの境界線は恣意的に決めることになるため、人によって解釈が異なるなどの問題が発生します。このように、教師あり学習教師なし学習では、どちらも一長一短なところがありそうです。


細胞種推定方法は、教師あり学習教師なし学習のどちらも存在します。今回はscNymという、RNA-Seq解析用の機械学習ライブラリを使います。scNymでは、教師あり学習教師なし学習を両方とも使用しており、ラベル付きデータとラベル無しデータの両方を使ってモデルを学習させるという手法が採られているようです。


scNymで細胞種を推定する


今回は、scNymの制作者が提供している学習済みモデルをそのまま利用します。このモデルでは、Tabula Murisという大規模マウスデータセットを使ってデータパターンの学習が行われたようです。

それでは、scNymの実行方法をざっと紹介します。なお、以下のプログラムは全てGoogle Colaboratory上で実行しました。


まずは、必要なパッケージをインポートします。


import os
import numpy as np
import pandas as pd
import scanpy as sc
import scnym
from scnym.predict import Predicter
from scnym.utils import build_classification_matrix


足りないパッケージは、pip install <パッケージ名>などで適宜ダウンロードします。


次に、学習に必要なデータを実行環境にダウンロードします。


%%bash
mkdir ../downloads
wget -nv https://storage.googleapis.com/calico-website-mca-storage/20190604_tissue_specific_weights_h0256_l1.tar.gz \
    -O ../downloads/tissue_specific_weights.tar.gz
wget -nv https://storage.googleapis.com/calico-website-mca-storage/20190604_scnym_training_gene_names.txt \
    -O ../downloads/training_gene_names.txt
wget -nv https://storage.googleapis.com/calico-website-mca-storage/20190604_training_metadata.csv \
    -O ../downloads/training_metadata.csv
wget -nv https://storage.googleapis.com/calico-website-mca-storage/lung.h5ad \
    -O ../downloads/lung.h5ad
%%bash
cd ../downloads
tar xvf tissue_specific_weights.tar.gz
cd -


必要なファイルのダウンロードが完了したので、これらを読み込んで変数に格納します。


model_weights = '../downloads/tissue_specific_weights/Lung.pkl'
training_gene_names = np.loadtxt('../downloads/training_gene_names.txt', dtype='str')
training_metadata = pd.read_csv('../downloads/training_metadata.csv')
adata = sc.read_h5ad('../downloads/lung.h5ad')
sc.pp.normalize_total(adata, target_sum=1e6)  # CPM
sc.pp.log1p(adata)  # 対数変換


これで、必要なデータがすべて揃いました。


次に、scNymの学習済みモデルに入力できるようデータを整形します。データ行列(X)と正解ラベル(cell_types)の両方をここで作ります。


X = build_classification_matrix(
    X = np.asarray(adata.X.todense()),
    model_genes = training_gene_names,
    sample_genes = np.array(adata.var_names))
cell_types = sorted(training_metadata.loc[training_metadata.tissue=='Lung','cell_ontology_class'].unique().tolist())


これで入力データの準備が完了したので、いよいよscNymで細胞種推定を行います。

まずは、学習モデルのオブジェクトを作成します。


P = Predicter(model_weights = model_weights,
              n_genes = len(training_gene_names),
              n_cell_types = len(cell_types),
              labels = cell_types,
              n_hidden = 256,
              n_layers = 1,
              residual = True)


そして、predictメソッドを実行して学習を開始します。


predictions, class_names, probabilities = P.predict(X=X, output='prob')


あとはしばらく待つと、学習が完了します。

結果はclass_namesに渡されるので、この中身を元データのadataに貼り付けます。


class_names = np.array(class_names)
adata.obs['pred_type'] = class_names


これで、scNymによる細胞種推定は完了です。adata.obsを確認してみると、確かに細胞種の予測結果が格納されていることが分かります。


f:id:emoriiin979:20201225140343p:plain


おまけ


今回読み込んだlung.h5adには、論文で実際に使われたcell_type情報が格納されています。このcell_typeと、今回予測して得られたpred_typeがどれくらい一致しているかを確認してみました。


print('adata.obs[\'cell_type\']との整合率: {:.2f} %'.format(
    sum(adata.obs['cell_type'] == adata.obs['pred_type']) / len(adata.obs['cell_type']) * 100))


結果は95.44 %でした。概ね一致していますが、一部異なる細胞種を選択してしまっているようです。これは、前処理方法が論文通りに実行できていないとか、学習パラメータが一致していないとか、様々な原因が考えられそうです。


まとめ


本記事では、scNymを使って細胞種の推定を行いました。今回は実装が簡単そうだったのでscNymを使用しましたが、もちろん他にも細胞種を推定する方法がたくさんあるので、自分に合ったやり方を見つけると良いと思います。

参考として、シングルセルRNA-Seq解析のツールを紹介しているscRNA-toolsというサービスもあるので、このようなサービスを駆使してscNym以外のツールも探してみてください。


以上です。