R语言 将lapply中的列用于data.table

rqdpfwrv  于 2023-03-20  发布在  其他
关注(0)|答案(4)|浏览(136)

我有一个data.table,它有几个列(可以是动态的列数),我想对它们应用最小值,每列都有自己的最小值。
data.table的基本版本如下所示:

library(data.table)
dt <- data.table(
  urn = 1:10,
  col1 = 5:14,
  col2 = 11:20
)
  • 注意:我只包含了两列,列中的值需要为reprex的最小值。可能会有更多列,因此尝试稍微动态地编写代码。*

我的方法是嵌套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)
  })]

目前,第一种方法将所有行设置为各自的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

如果有一个解决方案允许动态地对与col<number>匹配的列进行编号,那就太好了。

lkaoscv7

lkaoscv71#

这里你实际上是在尝试同时循环两个列表/向量,而lapply并不适合这样做,所以mapply在这里会很有用:

library("data.table")

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)

dt[,
   (my_cols) := mapply(function(x, y) {
     ifelse(x < y, y, x)
   },
   x = .SD,
   y = min_vals,
   SIMPLIFY = FALSE), .SDcols = my_cols]

为了确保只对所需的列应用函数,还需要告诉它对数据进行子集化,以便只保留所需的列(.SD是包含my_cols中列的数据子集)。

cxfofazt

cxfofazt2#

我们可以使用Map代替lapply,正如@罗兰在注解中指出的那样,i)在.SD上循环作为第一个输入(用mycols指定.SDcols),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

数据来自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)

创建于2023年3月20日,使用reprex v2.0.2

n3schb8v

n3schb8v3#

另一种方法是使用set()

for(i in seq_along(min_vals)) set(dt,which(my_cols[i]<min_vals[i]), my_cols[i]<min_vals[i], min_vals[i])

输出:

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
jexiocij

jexiocij4#

使用 forloop

for(i in seq_along(min_vals)){
  dt[ get(my_cols[ i ]) < min_vals[ i ], (my_cols[ i ]) := min_vals[ i ] ]
  }

相关问题