2

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

4

1 回答 1

2

在 R 中,每个操作都是一个函数调用,包括赋值。您可以?Extract在控制台中输入,您将看到一些基本运算符的文档,例如[<-[[<-$<-。S4 对象还有一个特殊的运算符:slot<-. 因此,每当您执行类似的操作时,也可以使用S4obj@x <- "foo"函数调用。`slot<-`(S4obj, "x", value="foo")这意味着你可以做你想做的事:

Map("slot<-", seurat.objects, "meta.data", value=metadata)

但是,您应该注意一个问题。R 通常具有 copy-on-modify 语义,这意味着在修改对象之前对其进行复制。例如:

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),以下也修改了原始对象而不复制:

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)
于 2019-04-27T10:23:27.950 回答