【问题标题】:set multiple columns in R `data.table` with a named list and `:=`在 R `data.table` 中使用命名列表和 `:=` 设置多个列
【发布时间】:2021-04-02 10:03:52
【问题描述】:

使用:= 创建新列是我最喜欢的data.table 功能之一。我知道使用它一次添加多个列的两种方法。这是一个简单的例子

dt <- data.table("widths" = seq(2, 10, 2), "heights" = 8:4)
dt
   widths heights
1:      2       8
2:      4       7
3:      6       6
4:      8       5
5:     10       4

假设我想添加两列,一列用于面积,另一列用于周长。第一种方法是调用,例如

new_cols <- c("areas", "perimeters")

my_fun <- function(x, y){
  areas <- x * y
  perimeters <- 2*(x + y)
  return(list(areas = areas, perimeters = perimeters))
}

dt[ , (new_cols) := my_fun(widths, heights)]
dt
   widths heights areas perimeters
1:      2       8   16        20
2:      4       7   28        22
3:      6       6   36        24
4:      8       5   40        26
5:     10       4   40        28

等价地,我们可以使用:=的函数形式如下:

dt[ , `:=`("areas" = widths * heights, "perimeters" = 2*(widths + heights))]

这两种方法都需要提前输入新列的名称。您可以手动输入它们,您可以在创建列之前将它们保存在一个对象中,或者您可以在:= 的左侧有一个生成名称的函数。我不知道的是一种在一次调用中同时获取名称和输出到:= 的方法。

有没有办法做到这一点?这是我希望做的一个例子:

dt[ , (new_cols) := NULL] # delete the previously added area and perimeter cols.
dt[ , `:=`(my_fun(widths, heights))]
dt
   widths heights areas perimeters
1:      2       8   16        20
2:      4       7   28        22
3:      6       6   36        24
4:      8       5   40        26
5:     10       4   40        28

理想情况下,有一种方法可以让:= 看到my_fun() 返回名称,然后将这些名称用作新列的名称。我知道上面会产生一个错误,但我想知道是否有一种简单的方法可以获得所需的功能,因为这在有很多列或列名取决于函数输入的较大问题中很有用。

编辑: 我正在寻找的关键是通过引用分配这些列的方法,即使用:= 或 set(),我还想将输出的类保持为data.table

【问题讨论】:

  • dt[ ,c(mget(names(.SD)),my_fun(widths, heights))],或者可能是cbind(dt, dt[, my_fun(widths, heights)]),但他们都没有就地做任何事情
  • 谢谢。 mget() 选项很好,但我正在寻找的关键是使用:= 或 set() 进行就地更新。我已经编辑了这个问题以明确这一点。
  • 我认为dt[, do.call(":=", my_fun(widths, heights))] 理论上会完全按照您的意愿行事,但目前无法正常工作。我已经提交了一个问题github.com/Rdatatable/data.table/issues/4950
  • 感谢您提交问题。内置的东西真的很棒,因为这将允许在这种情况下使用 by 和所有其他 data.table 工具。

标签: r data.table


【解决方案1】:

评论过长。不漂亮:

dt[, {
    a <- my_fun(widths, heights)   
    for (x in names(a))
        set(dt, j=x, value=a[[x]])
}]

或者你可以将dt传递给你创建的函数?

【讨论】:

  • 感谢您的解决方案。我接受它,因为它可以满足我的要求。如果您对如何在与by= 分组时轻松扩展此功能有任何想法,那就太好了。
  • 也许添加 by 参数和 i 与 .I
【解决方案2】:

我不认为你在寻找这个,但它有效。

data.frame(dt, my_fun(dt$widths, dt$heights))

#  widths heights areas perimeters
#1      2       8    16         20
#2      4       7    28         22
#3      6       6    36         24
#4      8       5    40         26
#5     10       4    40         28

很遗憾,data.table(dt, my_fun(dt$widths, dt$heights)) 不起作用。

【讨论】:

  • 谢谢,但这不是我想要的。我想维护 data.table 类并添加新列而不复制 dt
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多