将一个字符向量列表转换为二进制矩阵

10

我正在使用 R 进行工作,并拥有一个命名的字符向量列表。每个向量都描述了生物通路中存在的基因。

请看以下示例:

gene_sets = list(pathwayX= c("Gene3"),pathwayY= c("Gene2", "Gene3"),pathwayz= c("Gene1", "Gene2","Gene3"))

> gene_sets
$pathwayX
"Gene3"

$pathwayY
"Gene2" "Gene3"

$pathwayZ
"Gene1" "Gene2" "Gene3"
我想做的是将列表转换为二进制矩阵,以基因作为列,通路作为行。0表示通路中不存在该基因,1则表示通路存在该基因。
Gene1 Gene2 Gene3
pathwayX 0 0 1
pathwayY 0 1 1
pathwayZ 1 1 1
5个回答

7
一个想法是将 tablestack 结合使用,即:
t(table(stack(gene_sets)))

          values
ind        Gene1 Gene2 Gene3
  pathwayX     0     0     1
  pathwayY     0     1     1
  pathwayz     1     1     1

6
我们可以使用。
t(+sapply(gene_sets, "%in%", x = c("Gene1", "Gene2", "Gene3")))

如果您想动态获取c("Gene1", "Gene2", "Gene3"),我们可以这样做:
GeneID <- sort(unique(unlist(gene_sets)))

mat <- t(+sapply(gene_sets, "%in%", x = GeneID))  ## matrix output
colnames(mat) <- GeneID
#         Gene1 Gene2 Gene3
#pathwayX     0     0     1
#pathwayY     0     1     1
#pathwayz     1     1     1

data.frame(mat)  ## data.frame output

我的印象是,基因问题通常是大规模而稀疏的。如果你在现实中有数十万个基因和通路,以下的稀疏矩阵解决方案是最佳选择。

pathwayID <- names(gene_sets)
n1 <- lengths(gene_sets, use.names = FALSE)  ## number of genes in each pathway
genesVec <- unlist(gene_sets, use.names = FALSE)
GeneID <- sort(unique(genesVec))
i <- rep(1:length(n1), n1)
j <- match(genesVec, GeneID)
Matrix::sparseMatrix(i = i, j = j, x = rep.int(1, length(i)),
                     dimnames = list(pathwayID, GeneID))
#3 x 3 sparse Matrix of class "dgCMatrix"
#         Gene1 Gene2 Gene3
#pathwayX     .     .     1
#pathwayY     .     1     1
#pathwayz     1     1     1

1
追踪 Quinten 的回答中的 mtabulate,我找到了激发这个函数的问答:从标签向量列表创建标签频率数据框。我已经投票支持那个问题。当我有时间时,我会更新我的答案并进行基准测试。 - Zheyuan Li

5
你还可以像这样使用 qdapTools 中的 mtabulate
gene_sets = list(pathwayX= c("gene3"),pathwayY= c("gene2", "gene3"),pathwayz= c("gene1", "gene2","gene3"))

library(qdapTools)
mtabulate(gene_sets)
#>          gene1 gene2 gene3
#> pathwayX     0     0     1
#> pathwayY     0     1     1
#> pathwayz     1     1     1

此代码块由reprex包(v2.0.1)于2022年7月18日创建。


3

这里提供了使用 tidyverse 的解决方案:

library(dplyr)
library(tibble)
as.data.frame(unlist(gene_sets)) %>% 
  transmute(gene = as.factor(`unlist(gene_sets)`)) %>% 
  rownames_to_column() %>% 
  mutate(rowname = str_remove(rowname, "[0-9]")) %>% 
  cbind((model.matrix(~ gene + 0, .) == 1)*1) %>% 
  rename_with(., ~str_replace_all(., "geneGene", "Gene")) %>% 
  group_by(rowname) %>% 
  summarise(across(-gene, ~sum(.)))

  rowname  Gene1 Gene2 Gene3
  <chr>    <dbl> <dbl> <dbl>
1 pathwayX     0     0     1
2 pathwayY     0     1     1
3 pathwayz     1     1     1

1

如果必须走这条路,以下是一个相对简洁的tidyverse方法。

library(dplyr)
library(purrr)
library(tibble)
library(tidyr)

map_dfr(gene_sets,
        ~ as_tibble_row(set_names(rep(1L, length(.x)), .x)), .id = "row") %>% 
  relocate(row, order(colnames(.))) %>% 
  mutate(across(-1, replace_na, 0))

# A tibble: 3 x 4
  row      Gene1 Gene2 Gene3
  <chr>    <int> <int> <int>
1 pathwayX     0     0     1
2 pathwayY     0     1     1
3 pathwayz     1     1     1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接