我正在尝试测试一系列列中的条件。数据看起来像这样
Name DPD_1 DPD_2 DPD_3 Default_flag
1: A 46 63 138 TRUE
2: B 12 82 33 FALSE
3: C 95 71 55 TRUE
4: D 57 133 116 TRUE
5: E 48 27 137 TRUE
Run Code Online (Sandbox Code Playgroud)
在代码中,我需要测试 DPD_1、DPD_2 或 DPD_3 中的任何一个是否大于 90,在这种情况下 Default_flag 设置为 TRUE。
我为此使用的代码如下
df1 <- data.table(Name = LETTERS[1:10],DPD_1 = sample(1:100,10),DPD_2 = sample(1:200,10),DPD_3 = sample(1:200,10) )
df1[,Default_flag := ifelse((DPD_1>=90 | DPD_2>=90 | DPD_3>=90 ),TRUE,FALSE)]
Run Code Online (Sandbox Code Playgroud)
现在问题出在一些数据集上,我需要将 DPD 检查从 DPD_1 增加到 DPD_24(检查 24 列,而不是当前示例中的 3 列)。无论如何我可以避免在 ifelse 语句中指定每个 DPDnumber。我很高兴失去 ifelse 语句,如果某些版本的 apply 可以工作,我也很乐意使用它。
我们可以在指定感兴趣的列之后使用Reducewith|.SDcols
df1[, Default_flag := Reduce(`|`, lapply(.SD, `>=`, 90)), .SDcols = DPD_1:DPD_3]
Run Code Online (Sandbox Code Playgroud)
根据OP的评论,如果我们需要创建一个函数来自动检测列名,则使用grep基于模式获取列名。下面的函数采用数据集、模式('pat')、要比较的值('val')和'n',即特定模式的列数
f1 <- function(dat, pat, val, n){
tmp <- as.data.table(dat)
nm1 <- head(grep(pat, names(tmp), value = TRUE), n)
tmp[, Default_flag := Reduce(`|`,lapply(.SD, `>=`, val)), .SDcols = nm1][]
}
f1(df1, "DPD", 90, 2)
f1(df1, "DPD", 90, 3)
Run Code Online (Sandbox Code Playgroud)
根据@aelwan 的请求,使用的选项tidyverse是
library(tidyverse)
f2 <- function(dat, pat, val, n){
pat <- quo_name(enquo(pat))
nm1 <- head(grep(pat, names(dat), value = TRUE), n)
dat %>%
mutate_at(vars(nm1), funs(.>= val)) %>%
select_at(nm1) %>%
reduce(`|`) %>%
mutate(dat, Default_flag = .)
}
f2(df1, DPD, 90, 2)
f2(df1, DPD, 90, 3)
Run Code Online (Sandbox Code Playgroud)
identical(f1(df1, "DPD", 90, 2), as.data.table(f2(df1, DPD, 90, 2)))
#[1] TRUE
identical(f1(df1, "DPD", 90, 3), as.data.table(f2(df1, DPD, 90, 3)))
#[1] TRUE
Run Code Online (Sandbox Code Playgroud)