R语言-稀疏矩阵对象格式学习-重点理解稀疏矩阵对象的重构

稀疏矩阵几乎产生于所有的大型科学工程计算领域,记录样本特征值的稠密矩阵中很多记录值都是0,由于0不携带信息,因此耗费空间存储0元素是很浪费资源的行为。而且很多计算只对非零元素进行操作,将特征矩阵构建成稀疏矩阵,可以很容易的索引到非零元素,所以基于稀疏矩阵的数据运算,可是实现更低的资源占用和更快的计算速度。

单细胞领域,稀疏矩阵对于处理 scRNA-seq 表达谱数据是非常必要的,构建分析对象的时候它们消耗更低的内存。本文重点介绍 R语言 稀疏矩阵对象格式,稀疏矩阵的重构, 稀疏矩阵与稠密矩阵的相互转换。

三种类型的稀疏矩阵对象结构

首先,稀疏矩阵的一般格式主要有三种:

  • dgTMatrix ::: 创建未压缩的 三元组 稀疏矩阵 - 坐标格式的稀疏矩阵 - coo
    coo格式的稀疏矩阵以三元组(i,j,x)的形式记录非零条目
    • i ## 非零元素的行号【0-based索引值】
    • j ## 非零元素的列号【0-based索引值】
    • x ## 按列向量方向排列的非零元素 值(从左到右)
  • dgCMatrix ::: 创建列压缩的 三元组 稀疏矩阵 - 压缩系数矩阵 - csc - 更快的列检索速度
    csc格式的稀疏矩阵以三元组(i,p,x)的形式记录非零条目
    • i ## 非零元素的行号【0-based索引值】
    • p ## 从0开始, 记录值是对每列非零元素的个数的累加(从左到右)
    • x ## 按列向量方向排列的非零元素 值 (从左到右)
  • dgRMatrix ::: 创建行压缩的 三元组 稀疏矩阵 - csr - 更快的行检索速度
    • p ## 从0开始, 记录值是对每行非零元素的个数的累加(从上到下)
    • j ## 非零元素的列号【0-based索引值】
    • x ## 按行向量方向排列的非零元素 值 (从上到下)
1、R 语言 Matrix包

      Matrix 包为扩展基本矩阵数据类型的密集和稀疏矩阵提供了一组 S4 类和应用于这些类对象的各种函数和运算符方法。>Matrix package - RDocumentation

install.packages("Matrix") ; library(Matrix)
2、R 语言 稠密矩阵 与 稀疏矩阵 的相互转换

构建一个测试用稠密矩阵:

library(dplyr)
counts <- data.frame(cell.1=c(2,0,0,8),  cell.2=c(4,4,0,9),cell.3=c(3,3,3,0),cell.4=c(3,3,3,3),row.names = paste0("gene.",seq(4))) %>% as.matrix() 
> counts
       cell.1 cell.2 cell.3 cell.4
gene.1      2      4      3      3
gene.2      0      4      3      3
gene.3      0      0      3      3
gene.4      8      9      0      3

> print( paste0("矩阵非零元素个数 ", sum( colSums(counts != 0)) ," 个") )
[1] "矩阵非零元素个数 12 个"
> is(counts, 'sparseMatrix') #判断为非 稀疏矩阵 对象
[1] FALSE
  • 通过 as( ) 方法转换 稠密矩阵 \Rightarrow 稀疏矩阵
sparse.gbm.T <- as(counts, "dgTMatrix")  ### convert to coo_matrix
sparse.gbm.C <- as(counts, "dgCMatrix")  ### convert to csc_matrix
sparse.gbm.R <- as(counts, "dgRMatrix")  ### convert to csr_matrix

创建列压缩的稀疏矩阵(csc_matrix)还可以用方法sparse.gbm <- Matrix::Matrix(counts, sparse = T),但是该方法在大型矩阵中较为低效。
三种稀疏矩阵对象在R语言中的结构str(sparse.gbm.*)

数据结构

关于压缩格式的稀疏矩阵对象中数据结构的 sparse.gbm.C@p 向量,该向量不是非零元素的行/列索引编号,它的值是对 数据压缩方向上 每个向量内非零元素个数的累加(如创建列压缩稀疏矩阵时,压缩方向为按列 向左到右 移动)。p向量的记录方式相比i/j记录非零元素索引号,有助于进一步减少稀疏矩阵对象存储大小。

p的计算

对于任意矩阵,都可以计算p
列向量的p c(0, cumsum(colSums(counts != 0)))
行向量的p c(0, cumsum(rowSums(counts != 0)))
通过p 可以解析出 压缩方向的 真是索引编号(i/j)

#通过 p向量 解析出 列压缩稀疏矩阵的 向量j [记录了每个非零元素的列编号]
> rep(1:sparse.gbm.C@Dim[2], diff(sparse.gbm@p)) 
[1] 1 1 2 2 2 3 3 3 4 4 4 4
> sparse.gbm.C@i
[1] 0 3 0 1 3 0 1 2 0 1 2 3
> sparse.gbm.C@x
[1] 2 8 4 4 9 3 3 3 3 3 3 3

> sparse.gbm.C@j 
Error: no slot of name "j" for this object of class "dgCMatrix"
#列压缩的稀疏矩阵用p向量记录了元素的列索引编号j,所以没有向量j
  • 通过 as( ) 方法转换 稀疏矩阵 \Rightarrow 稠密矩阵
 >as.matrix(sparse.gbm.T)
       cell.1 cell.2 cell.3 cell.4
gene.1      2      4      3      3
gene.2      0      4      3      3
gene.3      0      0      3      3
gene.4      8      9      0      3
3、重构sparseMatrix
sparse.gbm.C.new <- Matrix::sparseMatrix(
    i = sparse.gbm.C@i + 1 ,  # +1 转换 0-based编号  为R语言 1-based 编号方式
    p = sparse.gbm.C@p ,
    x = sparse.gbm.C@x,
    dims = sparse.gbm.C@Dim #矩阵的维度
    )

\color{red}{注意:}由于dgCMatrix对象的行/列索引值 i / j 是【0-based】的,而R中数据对象(如data.frame,vector)的索引值都是 【1-based】 的,所以在通过Matrix::sparseMatrix重构稀疏矩阵的时候,i/j的索引值要加1转换为【1-based】

除了按S4的方法从对象中取三元组信息,通过Matrix::summary()方法可以快速获取稀疏矩阵S4对象的(i,j,x)三元组,并用于重构 sparse_matrix。

> as.data.frame(summary(sparse.gbm.C))
   i j x
1  1 1 2
2  4 1 8
3  1 2 4
4  2 2 4
5  4 2 9
6  1 3 3
7  2 3 3
8  3 3 3
9  1 4 3
10 2 4 3
11 3 4 3
12 4 4 3
4、稀疏矩阵的一些运算

log2标准化: log2(sparse.gbm.C + 1 )
对行 求  和: Matrix::rowSums(sparse.gbm)
对行求均值: Matrix::rowMeans(sparse.gbm)
对列 求  和: Matrix::colSums(sparse.gbm)
对行求均值: Matrix::colMeans(sparse.gbm)

5、读写出稀疏矩阵
  • 读取
    readMM( "matrix.mtx")
  • 写出
    writeMM(sparse.gbm.C, "matrix.mtx");system("gzip --keep matrix.mtx")

参考资料
Working with a sparse matrix in R - Kamil Slowikowski (slowkow.com)
Instructions for using Python SciPy sparse matrix | Develop Paper
R convert matrix or data frame to sparseMatrix - Stack Overflow

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容