将 lapply 中的列与 data.table 一起使用

Dan*_*Dan 3 r data.table

我有data.table几个列(可以是动态数量的列),我想对其应用最小值。每列都有自己特定的最小值。

我的基本版本data.table如下所示:

library(data.table)
dt <- data.table(
  urn = 1:10,
  col1 = 5:14,
  col2 = 11:20
)
Run Code Online (Sandbox Code Playgroud)

注意:我只包含了两列,其中的值需要具有代表的最小值。可能有更多的列,因此尝试动态地对此进行编码。

我的方法是嵌套lapply语句等,但我不知道如何在lapply函数中调用我的列。

min_vals <- c(10, 15)
my_cols <- grep("^col", colnames(dt), value = TRUE)

## First approach
dt[,
  (my_cols) := lapply(min_vals, function(x) {
    my_cols[my_cols < x] <- x
  })]

## Second Approach
dt[,
  (my_cols) := lapply(min_vals, function(x) {
    ifelse(my_cols < x, x, my_cols)
  })]

Run Code Online (Sandbox Code Playgroud)

目前,第一种方法将所有行设置为相应的min_vals,而不仅仅是min_vals. 第二种方法根本不起作用,反而出错。

所需的输出如下所示:

dt
#       urn  col1  col2
#     <int> <int> <int>
#  1:     1    10    15
#  2:     2    10    15
#  3:     3    10    15
#  4:     4    10    15
#  5:     5    10    15
#  6:     6    10    16
#  7:     7    11    17
#  8:     8    12    18
#  9:     9    13    19
# 10:    10    14    20
Run Code Online (Sandbox Code Playgroud)

如果有一个解决方案允许动态匹配格式的列数,那就太好了col<number>

Tim*_*Fan 7

我们可以使用Mapand 代替lapplyand,正如评论中的@Roland 指出的那样,i) 循环.SD作为第一个输入(.SDcols用指定mycols)并使用 ii) 更快,fielse而不是ifelse

library(data.table)

dt[, (my_cols) := Map(\(x, m) fifelse(x < m, m, x),
                      .SD,
                      min_vals),
   .SDcols = my_cols]

dt
#>     urn col1 col2
#>  1:   1   10   15
#>  2:   2   10   15
#>  3:   3   10   15
#>  4:   4   10   15
#>  5:   5   10   15
#>  6:   6   10   16
#>  7:   7   11   17
#>  8:   8   12   18
#>  9:   9   13   19
#> 10:  10   14   20
Run Code Online (Sandbox Code Playgroud)

@Mwavu 建议在评论中pmax使用另一个不错的选择:fifelse

dt[, c(my_cols) := Map(\(x, y) pmax(x, y), .SD, min_vals), .SDcols = my_cols]
#> same result as above
Run Code Online (Sandbox Code Playgroud)

来自OP的数据

dt <- data.table(
  urn = 1:10,
  col1 = 5:14,
  col2 = 11:20
)

min_vals <- c(10, 15)
my_cols <- grep("^col", colnames(dt), value = TRUE)
Run Code Online (Sandbox Code Playgroud)

创建于 2023-03-20,使用reprex v2.0.2

  • 你不需要`get`,你应该切换到`fifelse`:`dt[, (my_cols) := Map(\(x, m) fifelse(x &lt; m, m, x), .SD, min_vals) , .SDcols = my_cols]` (2认同)