【问题标题】:Using lapply over list of data.tables to assign list member name as variable在 data.tables 列表上使用 lapply 将列表成员名称分配为变量
【发布时间】:2015-05-14 13:25:15
【问题描述】:

我有一个 data.tables 列表

library(data.table)

set.seed(27)
test <- list()
test$a <- data.table(x = rnorm(n = 10),
                     y = rnorm (n = 10))
test$b <- data.table(x = rnorm(n = 10),
                     y = rnorm (n = 10))

列表中的每个成员都有一个唯一的名称

test

在准备将这些多个表附加到单个“长”格式中,我想创建第三列,它是一个变量,它是通过函数的每个成员的名称(我需要定期执行此操作)。

当前工作(虽然不正确)代码:

lName.asVariable <- function(dataTableList) {
dataTableList <- lapply(X = dataTableList, FUN = function(x)(x[, Site :=names(dataTableList)]))
}

test <- lName.asVariable(test)
test

哪些输出

$a
               x           y Site
 1:  1.907162564 -1.28512736    a
 2:  1.144876890  0.03482725    b
 3: -0.764530737  1.57029534    a
 4: -1.457432503  0.15801005    b
...
$b
              x          y Site
 1: -0.57488122 -0.1520452    a
 2: -1.15190000 -0.9589459    b
 3:  0.08706853  1.8582198    a
 4: -0.07018075 -1.5747647    b
...

虽然我想要的是

$a
               x           y Site
 1:  1.907162564 -1.28512736    a
 2:  1.144876890  0.03482725    a
 3: -0.764530737  1.57029534    a
 4: -1.457432503  0.15801005    a
...
$b
              x          y Site
 1: -0.57488122 -0.1520452    b
 2: -1.15190000 -0.9589459    b
 3:  0.08706853  1.8582198    b
 4: -0.07018075 -1.5747647    b
...

阅读extract names of objects from list seq_along 可能是我需要的,尽管下面的代码会产生错误:

lName.asVariable <- function(dataTableList) {
    dataTableList <- lapply(X = seq_along(dataTableList), FUN = function(x)(x[, Site := names(dataTableList)]))
}

test <- lName.asVariable(test)
test

我不够敏锐,但无法弄清楚如何打包 seq_along 以正确引用 data.table。这甚至是正确的策略吗?

【问题讨论】:

  • 使用mapply(或Map)传递表格和名称:Map(function(x,.y)(x[, Site :=.y]), test, names(test))
  • 如果您考虑将rbind 列表添加到单个数据框,请尝试rbindlist(test, idcol=TRUE),它将列表元素的名称作为新的.id
  • @nicola - 谢谢,效果很好,虽然我对.y 的使用感到困惑,而不仅仅是y
  • @akun - 恐怕对上面的数据执行此操作会给我一个错误。 Error in rbindlist(test, idcol = TRUE) : unused argument (idcol = TRUE) 我发现了 rbindlist{data.table},尽管唯一记录在案的参数似乎是 use.namesfill
  • @DaveRGP 我使用的是devel 版本。我想这是最近介绍的。如果你想安装开发版,这里是链接github.com/Rdatatable/data.table/wiki/Installation

标签: r list data.table apply


【解决方案1】:

我不知道这种方式对你有用。但如果你想要结果,我相信下面是简单的方法,

 library(data.table)

set.seed(27)
test <- list()
test$a <- data.table(x = rnorm(n = 10),
                     y = rnorm (n = 10))
test$b <- data.table(x = rnorm(n = 10),
                     y = rnorm (n = 10))
test
test$a$Site <- "a"
test$b$Site <- "b"
test

$a
               x           y Site
 1:  1.907162564 -1.28512736    a
 2:  1.144876890  0.03482725    a
 3: -0.764530737  1.57029534    a
 4: -1.457432503  0.15801005    a
 5: -1.093468881 -0.74579947    a
 6:  0.295241218 -1.06880297    a
 7:  0.006885942 -1.62743793    a
 8:  1.157410886 -1.06858164    a
 9:  2.134637891 -0.02583971    a
10:  0.237844613  0.31957639    a

$b
              x          y Site
 1: -0.57488122 -0.1520452    b
 2: -1.15190000 -0.9589459    b
 3:  0.08706853  1.8582198    b
 4: -0.07018075 -1.5747647    b
 5: -2.99830401 -0.3981480    b
 6: -1.22399491  0.9686850    b
 7: -0.99707477  0.6711891    b
 8:  0.33571390  0.6788910    b
 9:  1.29534374 -0.1739613    b
10:  0.32775994  0.7890292    b

【讨论】:

  • 感谢您的提议,但如果我没看错,您是在手动指定 a 和 b 吗?我需要能够以编程方式生成 a 和 b。有时我可能会从 a 到 z 运行它,甚至 100 多个文件 :)
【解决方案2】:

seq_along 生成从 1 到列表长度的数字序列。然后,您可以使用中间索引变量来引用列表项和 names 项:

lapply(seq_along(test), function(i) test[[i]][,Site:=names(test[i])])
[[1]]
               x           y Site
 1:  1.907162564 -1.28512736    a
 2:  1.144876890  0.03482725    a
 3: -0.764530737  1.57029534    a
 4: -1.457432503  0.15801005    a
 5: -1.093468881 -0.74579947    a
 6:  0.295241218 -1.06880297    a
 7:  0.006885942 -1.62743793    a
 8:  1.157410886 -1.06858164    a
 9:  2.134637891 -0.02583971    a
10:  0.237844613  0.31957639    a

[[2]]
              x          y Site
 1: -0.57488122 -0.1520452    b
 2: -1.15190000 -0.9589459    b
 3:  0.08706853  1.8582198    b
 4: -0.07018075 -1.5747647    b
 5: -2.99830401 -0.3981480    b
 6: -1.22399491  0.9686850    b
 7: -0.99707477  0.6711891    b
 8:  0.33571390  0.6788910    b
 9:  1.29534374 -0.1739613    b
10:  0.32775994  0.7890292    b

请注意,lapply 的输出会丢失名称,因此您必须手动恢复它们。

【讨论】:

  • 我可能是错的,因为我不习惯data.table,但是在赋值中使用括号[] 会保留名称,即test[] &lt;- lapply(seq_along(test), function(i) test[[i]][,Site:=names(test[i])]),因此无需以这种方式手动恢复它们。
  • 我认为 for 循环中的相同内容会更好。我猜lapply 会生成数据的副本(因为它有一个返回值)。 for(i in seq_along(test){test[[i]][,Site:=names(test[i])]}
  • @PeterDee 是的,实际上由于 data.table 的工作方式,原始变量在没有赋值的情况下被修改,您可以忽略 lapply 输出
  • @DaveRGP data.table 就地修改,因此您无需单独分配。
  • @DaveRGP 您需要在循环后return 列表,但原始列表可能已经在全局工作区中进行了修改。 data.table 就地修改数据而不是复制。
【解决方案3】:

如果您的最终目标是将它们组合成一个data.table,那么在最新版本(1.9.5+)中,您可以一步完成:

rbindlist(test, idcol = 'Site')
#    Site            x           y
# 1:    a  1.907162564 -1.28512736
# 2:    a  1.144876890  0.03482725
# 3:    a -0.764530737  1.57029534
# 4:    a -1.457432503  0.15801005
# 5:    a -1.093468881 -0.74579947
# 6:    a  0.295241218 -1.06880297
# 7:    a  0.006885942 -1.62743793
# 8:    a  1.157410886 -1.06858164
# 9:    a  2.134637891 -0.02583971
#10:    a  0.237844613  0.31957639
#11:    b -0.574881218 -0.15204521
#12:    b -1.151900001 -0.95894585
#13:    b  0.087068535  1.85821984
#14:    b -0.070180754 -1.57476470
#15:    b -2.998304014 -0.39814797
#16:    b -1.223994910  0.96868503
#17:    b -0.997074773  0.67118912
#18:    b  0.335713896  0.67889104
#19:    b  1.295343743 -0.17396132
#20:    b  0.327759944  0.78902925

【讨论】:

  • @akrun 在 cmets 中稍微更完整地提到了这一点。唯一需要注意的是,正如我们发现的那样,您目前需要开发版本来实现此功能。
  • @DaveRGP 你的意思是上面我说 1.9.5+ 的部分? :)
  • @DaveRGP 没有 1.9.5 你可以使用lapply(1:length(test), function(i, tbls) if(nrow(tbls[[i]]) &gt; 0) data.table(Site = names(tbls[i]), tbls[[i]]) else data.table(Site = character(), tbls[[i]]), test)。如果你想拥有一个 data.table,只需将结果包装到rbindlist
猜你喜欢
  • 1970-01-01
  • 2020-10-18
  • 1970-01-01
  • 2020-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-02
相关资源
最近更新 更多