2024 单细胞 RNA
测序数据应用系列 1 预处理
对于单细胞 RNA
测序数据我们通常会进行一个预处理过程,这个也和大多数机器学习和深度学习项目一致。这里我们介绍以
h5 文件格式存储的单细胞 RNA
测序数据的预处理。预处理主要是对表达矩阵进行归一化和去除低表达基因和细胞。
数据预处理
读取计数数据(count data)
以 “ZINB-Based Graph Embedding Autoencoder for Single-Cell RNA-Seq
Interpretations” (scTAG)中读取存储单细胞 RNA 测序数据为例。
数据格式介绍
首先对 scTAG 中 h5 文件进行简要介绍。H5 文件是层次数据格式第 5
代的版本(Hierarchical Data
Format,HDF5),它是用于存储科学数据的一种文件格式和库文件。
h5 文件中有两个主要结构:组“group”和数据集“dataset”。一个 h5 文件就是
“group” 和 “dataset” 二合一的容器,group 名称为key,datasets 为
value。
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import numpy as np
def prepro(filename): """ 函数用于预处理数据文件。 参数: filename (str): 数据文件的路径名。 返回值: tuple: 一个包含两个元素的元组: - X (numpy.ndarray): 预处理后的表达矩阵。 - cell_label (numpy.ndarray): 细胞类型的标签数组。 """ data_path = filename mat, obs, var, uns = read_data(data_path, sparsify=False, skip_exprs=False) if isinstance(mat, np.ndarray): X = np.array(mat) else: X = np.array(mat.toarray()) cell_name = np.array(obs["cell_type1"]) cell_type, cell_label = np.unique(cell_name, return_inverse=True) return X, cell_label
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| import h5py import scipy as sp import numpy as np import scanpy as sc import pandas as pd
def read_data(filename, sparsify=False, skip_exprs=False): """ 从HDF5格式的数据文件中读取数据。 参数: filename (str): HDF5文件的路径名。 sparsify (bool): 是否将表达矩阵转换为稀疏矩阵,默认为False。 skip_exprs (bool): 是否跳过表达矩阵的加载,默认为False。 返回值: tuple: 包含四个元素的元组: - mat (scipy.sparse.csr_matrix 或 numpy.ndarray): 表达矩阵。 - obs (pandas.DataFrame): 观测信息。 - var (pandas.DataFrame): 变量信息。 - uns (dict): 未分类信息。 """ with h5py.File(filename, "r") as f: obs = pd.DataFrame(dict_from_group(f["obs"]), index=utils.decode(f["obs_names"][...])) var = pd.DataFrame(dict_from_group(f["var"]), index=utils.decode(f["var_names"][...])) uns = dict_from_group(f["uns"]) if not skip_exprs: exprs_handle = f["exprs"] if isinstance(exprs_handle, h5py.Group): mat = sp.sparse.csr_matrix(( exprs_handle["data"][...], exprs_handle["indices"][...], exprs_handle["indptr"][...]), shape=exprs_handle["shape"][...]) else: mat = exprs_handle[...].astype(np.float32) if sparsify: mat = sp.sparse.csr_matrix(mat) else: mat = sp.sparse.csr_matrix((obs.shape[0], var.shape[0])) return mat, obs, var, uns
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| import h5py
class dotdict(dict): """ 创建一个字典的子类,它允许使用点符号(.)来访问字典键,就像访问对象属性一样。 方法: __getattr__(self, key): 通过点符号访问字典中的值。 __setattr__(self, key, value): 通过点符号设置字典中的值。 __delattr__(self, key): 通过点符号删除字典中的值。 """ __getattr__ = dict.get __setattr__ = dict.__setitem__ __delattr__ = dict.__delitem__
def read_clean(data): """ 清理从HDF5文件读取的数据。 参数: data (numpy.ndarray): 需要清理的数据数组。 返回: 数据清理后的结果,可能是单个值或解码后的字符串数组。 断言: 确保传入的数据是NumPy数组类型。 """ assert isinstance(data, np.ndarray) if data.dtype.type is np.bytes_: data = utils.decode(data) if data.size == 1: data = data.flat[0] return data
def dict_from_group(group): """ 递归地将HDF5 Group对象转换为Python字典。 参数: group (h5py.Group): HDF5 Group对象,包含数据集和其他Group。 返回: dotdict: 包含所有子组和数据集的字典,可以使用点符号访问。 """ assert isinstance(group, h5py.Group) d = dotdict() for key in group: if isinstance(group[key], h5py.Group): value = dict_from_group(group[key]) else: value = read_clean(group[key][...]) d[key] = value return d
|
预处理(Pre-processing)
原始 scRAN-seq 读取计数数据由 Python 包 SCANPY
进行预处理。首先,过滤掉任何细胞中没有计数的基因。其次,计算大小因子,并根据文库大小对读取计数进行归一化,因此细胞间的总计数相同。形式上,如果我们将细胞
\(i\) 的库大小(总读取计数数)表示为
\(s_i\),则细胞 \(i\) 的大小因子为 \(s_i/median(s)\)。最后一步是对读数进行对数变换和缩放,以便计数值遵循单位方差和零均值。预处理的读取计数矩阵为模型的的输入。
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| import scipy as sp import scanpy as sc
def normalize(adata, copy=True, highly_genes=None, filter_min_counts=True, size_factors=True, normalize_input=True, logtrans_input=True): """ 对单细胞RNA测序数据进行标准化预处理。 参数: adata (AnnData 或 str): 输入的AnnData对象或文件路径。 copy (bool): 是否在操作前复制输入数据,默认为True。 highly_genes (int 或 None): 选择高变基因的数量。如果为None,则不选择。 filter_min_counts (bool): 是否过滤掉表达量低的基因和细胞,默认为True。 size_factors (bool): 是否计算并应用大小因子(size factors)进行标准化,默认为True。 normalize_input (bool): 是否对输入数据进行标准化,默认为True。 logtrans_input (bool): 是否对输入数据进行对数转换,默认为True。 返回: AnnData: 经过预处理后的AnnData对象。 """ if isinstance(adata, sc.AnnData): if copy: adata = adata.copy() elif isinstance(adata, str): adata = sc.read(adata) else: raise NotImplementedError norm_error = 'Make sure that the dataset (adata.X) contains unnormalized count data.' assert 'n_count' not in adata.obs, norm_error if adata.X.size < 50e6: if sp.sparse.issparse(adata.X): assert (adata.X.astype(int) != adata.X).nnz == 0, norm_error else: assert np.all(adata.X.astype(int) == adata.X), norm_error if filter_min_counts: sc.pp.filter_genes(adata, min_counts=1) sc.pp.filter_cells(adata, min_counts=1) if size_factors or normalize_input or logtrans_input: adata.raw = adata.copy() else: adata.raw = adata if size_factors: sc.pp.normalize_per_cell(adata) adata.obs['size_factors'] = adata.obs.n_counts / np.median(adata.obs.n_counts) else: adata.obs['size_factors'] = 1.0 if logtrans_input: sc.pp.log1p(adata) if highly_genes != None: sc.pp.highly_variable_genes(adata, min_mean=0.0125, max_mean=3, min_disp=0.5, n_top_genes=highly_genes, subset=True) if normalize_input: sc.pp.scale(adata) return adata
|
参考
[1] H5文件简介以及python对h5文件的操作
[2] .h5文件的写入和读取(HDF5)
[3] .h5图像文件(数据集)的读取并存储工具贴(二)
[4] ZINB-based Graph
Embedding Autoencoder for Single-cell RNA-seq Interpretations