如何将列附加到列表中的 data.frames,其中该列应包含通过计算读出的那些 data.frames 的结构信息?

How to append a column to data.frames in a list where the column shall contain computationally read out structural information of those data.frames?

我有一些数据在 R 中读取和修改。对于一个最小的、可重现的示例 (reprex),我想将数据作为“在 R 中”的表示来提供,以传达数据结构:

读入数据的代码:

paths <- sprintf("filenames%02d.out", 1:26)
interim <- lapply(paths, read.table, header=FALSE, sep="\t", dec=".", na.strings="NA")
new_col_name <- c("Pos", "LRTD")
out <- lapply(interim, setNames, nm = new_col_name)

现在,lapply(out, head) 允许我们查看数据的 R 内部表示:

[[1]]
     Pos LRTD
1      0    0
2  70557    0
3 104076    0
4 163349    0
5 258229    0
6 356613    0

[[2]]
     Pos LRTD
1      0    0
2 171603    0
3 268756    0
4 456513    0
5 594904    0
6 663581    0

[[3]]
     Pos  LRTD
1      0 0.000
2 171960 0.370
3 217096 0.358
4 254484 0.338
5 320866 0.366
6 432642 0.382

{...}

[[26]]
     Pos LRTD
1      0    0
2 185161    0
3 234971    0
4 273218    0
5 319689    0
6 379800    0

所以它是一个 listdata.frame 具有 26 个元素。在这里,我想把我们在上面看到的数字称为方括号,所以数字 [[1]][[2]][[3]] 等等直到 [[26]],作为“元素描述符”。

现在我想做的是将第三列附加到 list 中的所有 data.frame,其中该列包含通过计算读出的 data.frame 的结构信息. 详细地说,我想将给定 data.frame 的元素描述符添加到它们各自的 data.frame 中。请记住,结果应如下所示:

[[1]]
     Pos LRTD   Chr
1      0    0   1
2  70557    0   1

[[2]]
     Pos LRTD   Chr
1      0    0   2
2 171603    0   2

[[3]]
     Pos  LRTD   Chr
1      0 0.000   3
2 171960 0.370   3

{...}

[[26]]
     Pos LRTD   Chr
1      0    0   26
2 185161    0   26

由于我很清楚这一点,我目前的解决方案是伪代码:

lapply(out, function(x) { x$Chr <- rep("element descriptor","lenght of list");return(x)})

我知道我可以用 rapply(out, length) 得到相应 data.frame 的长度,但到目前为止我还没有得到 rapply 在我的 lapply 中工作来自上方的命令。

还有,如何在代码中引用元素描述符?

Map 很适合这个。

Map(function(x, ind) transform(x, Chr = ind), out, seq_along(out))
# [[1]]
#      Pos LRTD Chr
# 1      0    0   1
# 2  70557    0   1
# 3 104076    0   1
# 4 163349    0   1
# 5 258229    0   1
# 6 356613    0   1
# [[2]]
#      Pos LRTD Chr
# 1      0    0   2
# 2 171603    0   2
# 3 268756    0   2
# 4 456513    0   2
# 5 594904    0   2
# 6 663581    0   2
# [[3]]
#      Pos  LRTD Chr
# 1      0 0.000   3
# 2 171960 0.370   3
# 3 217096 0.358   3
# 4 254484 0.338   3
# 5 320866 0.366   3
# 6 432642 0.382   3
# [[4]]
#      Pos LRTD Chr
# 1      0    0   4
# 2 185161    0   4
# 3 234971    0   4
# 4 273218    0   4
# 5 319689    0   4
# 6 379800    0   4

如果您的“元素描述符”确实是名称,则将其替换为

Map(function(x, ind) transform(x, Chr = ind), out, names(out))

它会有效地做同样的事情。

如果您对 lapply 感到满意并想知道这与那个的比较,那么 Map 的等效 lapply 将是:

lapply(names(out), function(nm) transform(out[[nm]], Chr = nm))

您甚至可以使用

编写一些代码
Map(transform, out, Chr = seq_along(out))
Map(transform, out, Chr = names(out))

(与上面相同的输出)。这恰好有效,因为我们可以在 Map 中使用命名参数,这些参数传递给 f=(函数)参数,在本例中为 transform


数据:

out <- list(structure(list(Pos = c(0L, 70557L, 104076L, 163349L, 258229L, 356613L), LRTD = c(0L, 0L, 0L, 0L, 0L, 0L)), class = "data.frame", row.names = c("1", "2", "3", "4", "5", "6")), structure(list(Pos = c(0L, 171603L, 268756L, 456513L, 594904L, 663581L), LRTD = c(0L, 0L, 0L, 0L, 0L, 0L)), class = "data.frame", row.names = c("1", "2", "3", "4", "5", "6")), structure(list(Pos = c(0L, 171960L, 217096L, 254484L, 320866L, 432642L), LRTD = c(0, 0.37, 0.358, 0.338, 0.366, 0.382)), class = "data.frame", row.names = c("1", "2", "3", "4", "5", "6")), structure(list(Pos = c(0L, 185161L, 234971L, 273218L, 319689L, 379800L), LRTD = c(0L, 0L, 0L, 0L, 0L, 0L)), class = "data.frame", row.names = c("1", "2", "3", "4", "5", "6")))

涉及 purrr 的一个选项可能是:

imap(out, ~ update_list(.x, Chr = .y))

[[1]]
     Pos LRTD Chr
1      0    0   1
2  70557    0   1
3 104076    0   1
4 163349    0   1
5 258229    0   1
6 356613    0   1

[[2]]
     Pos LRTD Chr
1      0    0   2
2 171603    0   2
3 268756    0   2
4 456513    0   2
5 594904    0   2
6 663581    0   2

[[3]]
     Pos  LRTD Chr
1      0 0.000   3
2 171960 0.370   3
3 217096 0.358   3
4 254484 0.338   3
5 320866 0.366   3
6 432642 0.382   3

[[4]]
     Pos LRTD Chr
1      0    0   4
2 185161    0   4
3 234971    0   4
4 273218    0   4
5 319689    0   4
6 379800    0   4

显然,所有文件都具有相似的结构,即列的顺序和类型相同(名称可能不同)。因此,我希望您不要介意我提出一种完全不同的方法,它不能回答您的实际问题,但可能有助于解决我认为是潜在问题的问题。

在这种情况下,我的首选方法是将所有文件合并到一个大型数据集中,其中在 id 列中为每一行指示来源(OP 元素描述符 Chr).

所以,这是我使用我喜欢的工具集会做的事情

library(data.table)
library(magrittr) 
new_col_name <- c("Pos", "LRTD")
paths <- sprintf("filenames%02d.out", 1:26)
out <- lapply(paths, read.table, header=FALSE, sep="\t", dec=".", na.strings="NA") %>%
  rbindlist(use.names = FALSE, idcol = "Chr") %>%
  setnames(old = 2:3, new = new_col_name)
    Chr    Pos  LRTD
 1:   1      0 0.000
 2:   1  70557 0.000
 3:   1 104076 0.000
 4:   1 163349 0.000
 5:   1 258229 0.000
 6:   1 356613 0.000
 7:   2      0 0.000
 8:   2 171603 0.000
 9:   2 268756 0.000
10:   2 456513 0.000
11:   2 594904 0.000
12:   2 663581 0.000
13:   3      0 0.000
14:   3 171960 0.370
15:   3 217096 0.358
16:   3 254484 0.338
17:   3 320866 0.366
18:   3 432642 0.382
19:   4      0 0.000
20:   4 185161 0.000
21:   4 234971 0.000
22:   4 273218 0.000
23:   4 319689 0.000
24:   4 379800 0.000
    Chr    Pos  LRTD

因此,对于一个大型数据集中的所有数据,我们可以对整列进行操作,而无需调用 lapply() 来处理每个块,但我们可以按 Chr 分组或子集,如果必要的。这种方法在很多情况下简化了我的工作流程。