Sparse行列とgene expressionデータ
##Sparsityとは
スパース行列とは、ほとんどの要素がゼロである行列のことです。例えば、10,000 × 10,000の行列で、非ゼロ要素が100個しかない場合、99.99%の要素がゼロになります。このような行列を「スパース (sparse)」と呼び、逆にゼロでない要素が多い行列を「デンス (dense)」と呼びます。
バイオインフォマティクスでは、シングルセルRNA-seqデータのような「細胞 × 遺伝子」の巨大な行列を扱いますが、各細胞で発現している遺伝子は全遺伝子のごく一部のため、データは極めてスパースになります。
##Sparse表現のメリット
scipy.sparseの関数を使うとsparseな行列を表現することができます。このメリットを端的にいうとデータ効率化と計算効率化の二面からsparse表現が採用されます。
https://docs.scipy.org/doc/scipy/reference/sparse.html
通常、10,000 × 10,000の行列を密行列 (dense matrix) として保存すると、1億個の要素すべてを保存する必要があります。float64型の場合、8バイト × 1億 = 800MBのメモリが必要です。
しかし、例えばCOOという表現方法だと、非ゼロ要素の座標と値だけを保存すればよいため、非ゼロ要素が10,000個の場合、約240KB程度で済みます。これはメモリ使用量にして約3,000分の1の節約になり、行列が大きくなればなるほどこの節約効果が絶大なものになることが分かります。
##scipy.sparseを使った表現方法
###COO (Coordinate)
COO (Coordinate) 形式は、最もシンプルなスパース行列の表現方法です。非ゼロ要素の行インデックス、列インデックス、値の3つの配列で行列を表現します。
例えば、(0,2)=5.0、(1,1)=3.0 という2つの非ゼロ要素を持つ行列は、row=[0,1], col=[2,1], data=[5.0,3.0] として保存されます。COO形式は構築が高速で、異なるスパース形式への変換が容易という利点があります。
###CSR (Compressed Sparse Row)
AnnDataでも使われている手法がCSRになります。
AnnDataでは各行が一つの細胞のデータを表現している、すなわち行方向が遺伝子・列方向が細胞という変数を表しています。
For instance, in scRNA-seq data, each row corresponds to a cell with a barcode, and each column corresponds to a gene with a gene id.
CSRによるsparse matrix表現を行うことで、細胞間のカウントデータに対して種々のメトリクスを計算することを効率化しているということになります。
##他にもSparse表現が使われている場面
調べてみたところ、非常に多くのバイオインフォマティクスツールにおいてsparse表現が使われていました。
- Seurat
Rにおいて最も著名なscRNA-seq解析パッケージのSeuratですが、MatrixパッケージのdgMatrixというCSC形式を利用しています。
- QIIME 2 / BIOM
マイクロバイオーム解析では「サンプル × 細菌種」の巨大な行列を扱いますが、各サンプルに存在する細菌種はごく一部のため、データは極めてスパースです。BIOM (Biological Observation Matrix) 形式は、このようなスパースデータを効率的に保存・処理するために設計されており、QIIME 2 などの主要な解析パイプラインで採用されています。
- ArchR / Signac
シングルセル ATAC-seq (scATAC-seq) は、scRNA-seq よりもさらにスパース性が高いデータです。ゲノム上の数十万〜数百万の領域に対して、各細胞で開いている領域はごくわずかであり、データのほとんどが 0 になります。R の Signac や ArchR は、この巨大なスパースデータを扱うために、ディスクベースの HDF5 スパース形式などを利用しています。
- Hail / PLINK
集団遺伝学では、数万人規模の個人と数百万の SNP からなる巨大な遺伝子型行列を扱います。多くの SNP で変異を持つ人は少数派のため、行列は非常にスパースになります。Hail などのツールは、このようなテラバイト級のジェノタイプデータを効率的に分散処理するために、スパースなデータ構造を採用しています。
- NetworkX / igraph
遺伝子制御ネットワークやタンパク質間相互作用ネットワークは、隣接行列で表現できます。ある遺伝子が相互作用する相手は全遺伝子の中のごく一部のため、隣接行列は非常にスパースです。Python の NetworkX や R/Python の igraph は、大規模なネットワークをメモリ効率よく扱うために、内部的にスパース行列を利用しています。
##結び
AnnDataのdocumentationを読んでいる過程でsparse行列に関してさらっと記述されていたので、気になって調べてみました。
Sparse行列表現は数学的には通常の表現と同じですが、メモリ効率ではやはりメリットが大きいのか、使われる場面は非常に多いみたいですね。
-
Rは歴史的にCSCをスパース行列として用いることが多いです。 ↩