我有一个S4
类的Seurat
个对象的列表,其中每个对象都有几个slots
:
> lapply(seurat.objects, slotNames)
$gw14
[1] "raw.data" "data" "scale.data" "var.genes" "is.expr"
[6] "ident" "meta.data" "project.name" "dr" "assay"
[11] "hvg.info" "imputed" "cell.names" "cluster.tree" "snn"
[16] "calc.params" "kmeans" "spatial" "misc" "version"
$gw17
[1] "raw.data" "data" "scale.data" "var.genes" "is.expr"
[6] "ident" "meta.data" "project.name" "dr" "assay"
[11] "hvg.info" "imputed" "cell.names" "cluster.tree" "snn"
[16] "calc.params" "kmeans" "spatial" "misc" "version"
$gw18
[1] "raw.data" "data" "scale.data" "var.genes" "is.expr"
[6] "ident" "meta.data" "project.name" "dr" "assay"
[11] "hvg.info" "imputed" "cell.names" "cluster.tree" "snn"
[16] "calc.params" "kmeans" "spatial" "misc" "version"
$gw19
[1] "raw.data" "data" "scale.data" "var.genes" "is.expr"
[6] "ident" "meta.data" "project.name" "dr" "assay"
[11] "hvg.info" "imputed" "cell.names" "cluster.tree" "snn"
[16] "calc.params" "kmeans" "spatial" "misc" "version"
我想用第二个列表metadata
中的相应数据帧替换每个列表元素的每个@metadata槽中存储的数据帧。
> lapply(metadata, head)
$gw14
# A tibble: 98,879 x 7
cell.name nGene nUMI orig.ident pct.mito pct.ribo age
<chr> <int> <int> <chr> <dbl> <dbl> <chr>
1 AAACCTGAGAGGTTAT_1 598 1202 CGE 0.02 0.24 gw14
2 AAACCTGAGCAGGTCA_2 582 914 CGE 0.01 0.17 gw14
3 AAACCTGAGGAGCGAG_3 493 1225 CGE 0.01 0.43 gw14
4 AAACCTGAGGGCATGT_4 414 731 CGE 0.02 0.290 gw14
5 AAACCTGAGTGATCGG_5 449 794 CGE 0.03 0.27 gw14
6 AAACCTGCAAAGTGCG_6 1055 2439 CGE 0.02 0.25 gw14
7 AAACCTGCAATCGGTT_7 724 1485 CGE 0.01 0.23 gw14
8 AAACCTGCACTTGGAT_8 514 885 CGE 0 0.18 gw14
9 AAACCTGCAGACGCCT_9 593 1215 CGE 0.03 0.27 gw14
10 AAACCTGCAGCATACT_10 411 795 CGE 0.02 0.290 gw14
# ... with 98,869 more rows
$gw17
# A tibble: 61,578 x 7
cell.name nGene nUMI orig.ident pct.mito pct.ribo age
<chr> <int> <int> <chr> <dbl> <dbl> <chr>
1 AAACCTGAGAAGGACA_1 401 733 CGE 0.03 0.3 gw17
2 AAACCTGAGCACCGTC_2 351 687 CGE 0.01 0.33 gw17
3 AAACCTGAGCCAGAAC_3 408 824 CGE 0.01 0.3 gw17
4 AAACCTGAGTGGCACA_4 557 1041 CGE 0.01 0.25 gw17
5 AAACCTGCACACAGAG_5 1650 3609 CGE 0.02 0.19 gw17
6 AAACCTGCAGCCACCA_6 295 730 CGE 0.01 0.05 gw17
7 AAACCTGCAGTCGTGC_7 1136 2263 CGE 0.01 0.21 gw17
8 AAACCTGCATATGCTG_8 733 1561 CGE 0.01 0.26 gw17
9 AAACCTGCATTAGGCT_9 1344 3463 CGE 0.02 0.28 gw17
10 AAACCTGGTACCGCTG_10 915 2031 CGE 0.03 0.23 gw17
# ... with 61,568 more rows
$gw18
# A tibble: 113,918 x 7
cell.name nGene nUMI orig.ident pct.mito pct.ribo age
<chr> <int> <int> <chr> <dbl> <dbl> <chr>
1 AAACCTGAGCTAGTCT_1 1506 5420 CGE 0.03 0.37 gw18
2 AAACCTGAGGGCACTA_2 1177 3580 CGE 0.02 0.27 gw18
3 AAACCTGCAATCTGCA_3 1111 3204 CGE 0.04 0.33 gw18
4 AAACCTGCAATGAATG_4 1323 4864 CGE 0.04 0.4 gw18
5 AAACCTGCAGCCTTGG_5 1451 4840 CGE 0.02 0.23 gw18
6 AAACCTGCAGGTGGAT_6 1402 4685 CGE 0.02 0.2 gw18
7 AAACCTGCATCCTTGC_7 1917 6749 CGE 0.02 0.24 gw18
8 AAACCTGGTAAACACA_8 1224 3925 CGE 0.02 0.33 gw18
9 AAACCTGGTCATGCCG_9 2726 10896 CGE 0.03 0.28 gw18
10 AAACCTGGTGTAACGG_10 967 3034 CGE 0.03 0.290 gw18
# ... with 113,908 more rows
$gw19
# A tibble: 65,955 x 7
cell.name nGene nUMI orig.ident pct.mito pct.ribo age
<chr> <int> <int> <chr> <dbl> <dbl> <chr>
1 AAACCTGCAAGGCTCC_1 473 887 CGE 0 0.23 gw19
2 AAACCTGCACCAGCAC_2 582 1400 CGE 0.01 0.290 gw19
3 AAACCTGGTCTGATTG_3 570 1372 CGE 0.03 0.290 gw19
4 AAACCTGGTGCACTTA_4 573 1279 CGE 0.02 0.32 gw19
5 AAACCTGGTGTAATGA_5 617 1429 CGE 0.02 0.28 gw19
6 AAACCTGTCATAAAGG_6 1470 3837 CGE 0.02 0.26 gw19
7 AAACCTGTCCAACCAA_7 663 1720 CGE 0.02 0.33 gw19
8 AAACCTGTCTTAACCT_8 418 807 CGE 0.02 0.19 gw19
9 AAACGGGAGATGCCAG_9 1092 3306 CGE 0.02 0.45 gw19
10 AAACGGGAGTCCTCCT_10 1894 6252 CGE 0.04 0.32 gw19
# ... with 65,945 more rows
我能提出的最佳解决方案如下,但是我确信必须有更好的方法。
test <- lapply(names(seurat.objects) %>% setNames(nm = .),
function(x) {
seurat.objects[[x]]@meta.data <- metadata[[x]] %>%
column_to_rownames(. , var = "cell.name")
return(seurat.objects[[x]])
}
)
此解决方案在保留整个S4
对象的同时,仅修改了@metadata
槽,还保留了每个列表元素的名称,但这是一个复杂的路径...
感谢您的建议。
答案 0 :(得分:1)
在R中,每个操作都是一个函数调用,包括赋值。
您可以在控制台中输入?Extract
,然后会看到一些有关基本运算符的文档,
例如[<-
,[[<-
和$<-
。
S4对象还具有一个特殊的运算符:slot<-
。
因此,只要您执行S4obj@x <- "foo"
之类的操作,
也可以使用函数调用`slot<-`(S4obj, "x", value="foo")
。
这意味着您可以使用以下方法完成自己想做的事情:
Map("slot<-", seurat.objects, "meta.data", value=metadata)
但是,您应该注意一个陷阱。 R通常具有“修改时复制”语义, 这意味着在修改对象之前先对其进行复制。 例如:
vecs <- list(1:2, 3:4)
vecs2 <- lapply(vecs, "[<-", 1L, 0L)
> vecs
[[1]]
[1] 1 2
[[2]]
[1] 3 4
> vecs2
[[1]]
[1] 0 2
[[2]]
[1] 0 4
这并不总是适用, 环境和引用类具有不同的语义。 例如:
envs <- list(new.env(), new.env())
envs2 <- lapply(envs, "[[<-", "foo", "bar")
> sapply(envs, ls)
[1] "foo" "foo"
> sapply(envs2, ls)
[1] "foo" "foo"
在这种情况下,envs
中的环境在为envs2
进行修改之前没有被复制,
因此两个列表都包含相同的对象。
由于某些原因,我想知道它是否是一个错误(R v3.6.0),它是known bug,以下代码也修改了原始对象而不进行复制:
setClass("Foo", list(x="integer"))
s4s <- list(new("Foo", x=0L), new("Foo", x=1L))
s4s2 <- Map("slot<-", s4s, "x", value=list(2L, 3L))
> s4s
[[1]]
An object of class "Foo"
Slot "x":
[1] 2
[[2]]
An object of class "Foo"
Slot "x":
[1] 3
> s4s2
[[1]]
An object of class "Foo"
Slot "x":
[1] 2
[[2]]
An object of class "Foo"
Slot "x":
[1] 3
因此,如果要避免这种情况,请使用akrun建议的形式:
Map(function(x, y) { slot(x, "meta.data") <- y; x }, seurat.objects, metadata)