替换结构相同的S4对象列表的每个元素中@slot的值

时间:2019-04-25 04:06:59

标签: r dplyr lapply purrr s4

我有一个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槽,还保留了每个列表元素的名称,但这是一个复杂的路径... 感谢您的建议。

1 个答案:

答案 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)