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

Posted

技术标签:

【中文标题】如何将列附加到列表中的 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? 【发布时间】:2021-09-28 08:23:25 【问题描述】:

我有一些我在 R 中读入和修改的数据。对于一个最小的、可重现的示例 (reprex),我想将数据作为“in 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

所以它是data.frames 中的list,有26 个元素。在这里,我想将我们可以在上面看到的方括号中的数字称为“元素描述符”,因此将数字[[1]][[2]][[3]] 等等直到[[26]] 称为“元素描述符”。

现在我想做的是将第三列附加到list 中的所有data.frames,其中该列包含计算读出的data.frames 的结构信息。 具体来说,我想将给定data.frames 的元素描述符添加到它们各自的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

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

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

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

另外,如何在代码中引用元素描述符?

【问题讨论】:

【参考方案1】:

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")))

【讨论】:

感谢您的回答,尤其是您与lapply 的比较!比较有助于我更深入地了解解决方案,并且您的 Map 命令运行良好 - 谢谢!【参考方案2】:

涉及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

【讨论】:

也感谢您的回答。虽然我不得不承认我个人喜欢“香草”的答案,而不需要更多的包装。【参考方案3】:

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

在这种情况下,我首选的方法是将所有文件合并到一个大型数据集中,其中为 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 分组或子集。这种方法在很多情况下都简化了我的工作流程。

【讨论】:

事实上,我的下一个问题是如何将data.frame 列表元素连接到一个(大)单个data.frame。实际上,我已经尝试过问here,尽管当时我无法真正表达我想问的内容。所以感谢您提前回答我的串联问题!

以上是关于如何将列附加到列表中的 data.frames,其中该列应包含计算读取的那些 data.frames 的结构信息?的主要内容,如果未能解决你的问题,请参考以下文章

将列附加到新数据框

使用 R 将列表的元素保存为 data.frames

R - 子集列表data.frames由矢量值

SQL Server:将列转换为另一个并将其值附加到单独的列

将第N行的NAs插入到data.frames列表中,从列表中插入N行。

Python:将列附加到 PrettyTable 中的现有表