如何将列附加到列表中的 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.frame
s 中的list
,有26 个元素。在这里,我想将我们可以在上面看到的方括号中的数字称为“元素描述符”,因此将数字[[1]]
、[[2]]
、[[3]]
等等直到[[26]]
称为“元素描述符”。
现在我想做的是将第三列附加到list
中的所有data.frame
s,其中该列包含计算读出的data.frame
s 的结构信息。
具体来说,我想将给定data.frame
s 的元素描述符添加到它们各自的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 的结构信息?的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server:将列转换为另一个并将其值附加到单独的列