R在讀取和處理數據的過程中會將所有的變量和占用都儲存在RAM當中,這樣一來,對于海量的單細胞RNA-seq數據(尤其是超過250k的細胞量),即使在服務器當中運行,Seurat、metacell、monocle這一類的R包的使用還是會產生內存不足的問題。
但是最近我發現了一個基于python的單細胞基因表達分析包scanpy,能夠很好地在我這個僅4G內存的小破機上分析378k的細胞,并且功能豐富程度不亞于Seurat。它包含了數據預處理、可視化、聚類、偽時間分析和軌跡推斷、差異表達分析。根據官網描述,scanpy能夠有效處理超過1,000,000個細胞的數據集。
Scanpy – Single-Cell Analysis in Python:https://scanpy.readthedocs.io/en/latest/
安裝與數據下載
安裝好python3之后,終端運行:
pip install scanpy
若安裝過程出現問題,請參考:
https://scanpy.readthedocs.io/en/latest/installation.html
骨髓單細胞轉錄組測序數據下載地址:
https://preview.data.humancellatlas.org
Step0, 讀取數據
運行python
import numpy as np
import pandas as pd
import scanpy as sc
# 可以直接讀取10Xgenomics的.h5格式數據
adata = sc.read_10x_h5("/Users/shinianyike/Desktop/ica_bone_marrow_h5.h5"
, genome=None, gex_only=True)
adata.var_names_make_unique()
查看數據:
adata
AnnData object with n_obs × n_vars = 378000 × 33694
var: 'gene_ids'
共378000個細胞,33694個基因。
Step1, 數據預處理
這一步目的將數據進行篩選和過濾,一些測序質量差的數據會讓后續的分析產生噪音和干擾,因此我們需要將它們去除。
展示在所有的細胞當中表達占比最高的20個基因。
sc.pl.highest_expr_genes(adata, n_top=20)
基礎過濾:
去除表達基因200以下的細胞;
去除在3個細胞以下表達的基因。
sc.pp.filter_cells(adata, min_genes=200) # 去除表達基因200以下的細胞
sc.pp.filter_genes(adata, min_cells=3) # 去除在3個細胞以下表達的基因
adata
AnnData object with n_obs × n_vars = 335618 × 24888
obs: 'n_genes'
var: 'gene_ids', 'n_cells'
共335618個細胞,24888個基因。(可以發現細胞跟基因數量都減少了)
質量控制:
在測序后,有很大比例是低質量的細胞,可能是因為細胞破碎造成的胞質RNA流失,由于線粒體比單個的轉錄分子要大得多,不容易在破碎的細胞膜中泄漏出去,這樣一來就導致測序結果顯示線粒體基因的比例在細胞內占比異常高。這一步質量控制的目的就是將這些低質量的細胞去除掉。
計算線粒體基因占所有基因的比例:
mito_genes = adata.var_names.str.startswith('MT-')
# for each cell compute fraction of counts in mito genes vs. all genes
# the `.A1` is only necessary as X is sparse (to transform to a dense array after summing)
adata.obs['percent_mito'] = np.sum(
adata[:, mito_genes].X, axis=1).A1 / np.sum(adata.X, axis=1).A1
# add the total counts per cell as observations-annotation to adata
adata.obs['n_counts'] = adata.X.sum(axis=1).A1
作小提琴圖,查看線粒體基因占比分布:
sc.pl.violin(adata, ['n_genes', 'n_counts', 'percent_mito'],
jitter=0.4, multi_panel=True)
由于數據點實在太多,小提琴已被數據點覆蓋,無法顯示出來。
這里還可以做一個散點圖,也可以直觀地顯示出一些異常分布的數據點。
sc.pl.scatter(adata, x='n_counts', y='percent_mito')
sc.pl.scatter(adata, x='n_counts', y='n_genes')
adata
AnnData object with n_obs × n_vars = 335618 × 24888
obs: 'n_genes', 'percent_mito', 'n_counts'
var: 'gene_ids', 'n_cells'
335618個細胞,24888個基因;
下面這一步進行真正的過濾,根據上面做的圖,去除基因數目過多(大于等于4000)和線粒體基因占比過多(大于等于0.3)的細胞:
adata = adata[adata.obs['n_genes'] < 4000, :]
adata = adata[adata.obs['percent_mito'] < 0.3, :]
過濾后查看剩下多少細胞和基因。
adata
View of AnnData object with n_obs × n_vars = 328435 × 24888
obs: 'n_genes', 'percent_mito', 'n_counts'
var: 'gene_ids', 'n_cells'
328435個細胞,24888個基因。
數據標準化
在繪圖之前,還要進行一步數據標準化,將表達量用對數計算一遍,這樣有利于繪圖和展示。
sc.pp.normalize_per_cell(adata, counts_per_cell_after=1e4)
sc.pp.log1p(adata)
adata.raw = adata # 儲存標準化后的AnnaData Object
識別差異表達基因
sc.pp.highly_variable_genes(adata, min_mean=0.0125, max_mean=3, min_disp=0.5)
sc.pl.highly_variable_genes(adata)
將保守的基因去除,留下差異表達的基因用于后續分析。
adata = adata[:, adata.var['highly_variable']]
adata
View of AnnData object with n_obs × n_vars = 328435 × 1372
obs: 'n_genes', 'percent_mito', 'n_counts'
var: 'gene_ids', 'n_cells', 'highly_variable', 'means', 'dispersions', 'dispersions_norm'
328435個細胞,1372個基因。
回歸每個細胞總計數和線粒體基因表達百分比的影響。將數據放縮到方差為1。單細胞數據集可能包含“不感興趣”的變異來源。這不僅包括技術噪音,還包括批次效應,甚至包括生物變異來源(細胞周期階段)。正如(Buettner, et al NBT,2015)中所建議的那樣,從分析中回歸這些信號可以改善下游維數減少和聚類。
這一步高內存需求預警,建議清理電腦緩存,關閉后臺不使用的應用。
sc.pp.regress_out(adata, ['n_counts', 'percent_mito'])
/Users/shinianyike/anaconda3/lib/python3.6/site-packages/statsmodels/compat/pandas.py:56: FutureWarning: The pandas.core.datetools module is deprecated and will be removed in a future version. Please use the pandas.tseries module instead.
from pandas.core import datetools
Scale each gene to unit variance. Clip values exceeding standard deviation 10.
sc.pp.scale(adata, max_value=10)
Step2, 主成分分析
主成分分析是一種將數據降維的分析方法,是考察多個變量間相關性一種多元統計方法,研究如何通過少數幾個主成分來揭示多個變量間的內部結構,即從原始變量中導出少數幾個主成分,使它們盡可能多地保留原始變量的信息,且彼此間互不相關.通常數學上的處理就是將原來P個指標作線性組合,作為新的綜合指標。
sc.tl.pca(adata, svd_solver='arpack') # PCA分析
sc.pl.pca(adata, color='CST3') #繪圖
作碎石圖,觀測主成分的質量。這個圖用于選擇后續應該使用多少個PC,用于計算細胞間的相鄰距離。
sc.pl.pca_variance_ratio(adata, log=True)
在這里先將數據保存,便于后續操作的更改。
adata.write("pca_results.h5ad")
Step3, 聚類分析
計算細胞間的距離:
這里的參數就先按照默認值設定:
sc.pp.neighbors(adata, n_neighbors=10, n_pcs=40)
參數說明:
n_neighbors指的是每個點的鄰近點的數量,據評論區@小光amateur 所說neighbors的個數越多,聚類數會越少。
pc的數量依賴于上面所做的碎石圖,一般是選在拐點處的的主成分,只需要一個粗略值,不同的pc數量所產生的聚類形狀也不同。我后來更改為PC=16,效果比下圖要好一些。
將距離嵌入圖中:
sc.tl.umap(adata)
sc.pl.umap(adata, color=['CST3', 'NKG7', 'PPBP'])
sc.pl.umap(adata, color=['CST3', 'NKG7', 'PPBP'], use_raw=False)
聚類
sc.tl.louvain(adata)
sc.pl.umap(adata, color=['louvain'])
這里得到了29類細胞,每個顏色代表一種。
將數據保存。
adata.write("umap.h5ad")
尋找marker基因
marker基因通常是細胞表面抗原,用于定義出該細胞的細胞類型。
為了定義每個簇屬于什么細胞,根據基因的差異表達水平,將每個簇排名前25的基因導出。
sc.tl.rank_genes_groups(adata, 'louvain', method='wilcoxon')
sc.pl.rank_genes_groups(adata, n_genes=25, sharey=False)
下一步的工作是找出每一個簇的marker基因對應的細胞類型,這主要依靠一些數據庫或生物學的相關背景知識。
文章已發布到微信公眾號:百味科研芝士,歡迎關注。