r - 基于嵌套 if else 条件和比较 R 中列表中的值创建新列的有效方法
问题描述
输入 dt
-
dt <- data.frame(a_check=c(1,2,1,1,2),
b_check=c(0,1,NA,1,15),
c_check=c(1,0,0,1,NA),
d_check=c(1,1,1,0,0),
e_check=c(1,NA,0,1,1))
验证清单-
valid_values <- list(a_check= c(1,2,3), b_check= c(0,1),c_check=c(0,1,2),d_check="possitive integer",e_check="positive integer")
required_list <- list(a_check= 1, b_check= 1,c_check=0,d_check=1,e_check=0)
col_type_list <- list(a_check= "factor", b_check= "factor",c_check="continuous",d_check="continuous",e_check="continuous")
问题-
我试图通过使用以下多个ifelse
条件来获得低于所需的输出 -
- 如果该列
variable
需要required_list
并dt
包含NA
该列,则它应该给出error
(变量不能是 NA,因为它是必需的)。 - If
variable
iscontinuous
incol_type_list
than 它应该在 else 中只包含正值dt
(变量必须是正整数) - If
variable
isfactor
incol_type_list
than 它应该与valid_value
列表 else 中的值匹配(变量必须是以下值之一)。
我可以使用获得结果,nested for loops
但对于大型数据集来说根本没有效率。
我的代码-
param_names <- colnames(dt)
error_msg <- list()
error <- list()
for(i in 1:nrow(dt)){
for(j in 1:length(param_names))
{
if(get(param_names[j],required_list) %in% 1 & is.na(as.numeric(unlist(dt[param_names[j]]))[i]) == TRUE)
{
error_msg[j] <- paste0(toupper(param_names[j]), " cannot be NA because it is required")
}
## continuous variable check
else if(get(param_names[j],col_type_list)=="continuous"){
if (is.na(as.numeric(unlist(dt[param_names[j]]))[i]) | as.numeric(unlist(dt[param_names[j]]))[i] < 0) {
error_msg[j] <- paste0(toupper(param_names[j]), " must be a positive integer")
} else {
error_msg[j] <- NA
}
} else {
## factor variable check
if(!(as.numeric(unlist(dt[param_names[j]]))[i] %in% get(param_names[j],valid_values))){
error_msg[j] <- paste0(toupper(param_names[j]), " must be one of the following values ", paste(get(param_names[j],valid_values), collapse = '-'))
} else {
error_msg[j] <- NA
}
}
} ## end of inner for loop
error[i] <- paste(unlist(error_msg),collapse = " & ")
}## end of inner f
final_error <- unlist(error)
setDT(dt)
dt[,error := final_error]
dt[,error := gsub("NA & | NA \\s+ &", "\\1", error)]
dt[,error := gsub("& \\s+ NA | & NA", "\\1", error)]
输出-
> dt
a_check b_check c_check d_check e_check error
1: 1 0 1 1 1 NA
2: 2 1 0 1 NA E_CHECK must be a positive integer
3: 1 NA 0 1 0 B_CHECK cannot be NA
4: 1 1 1 0 1 NA
5: 2 15 NA 0 1 B_CHECK must be one of the following values 0-1 & C_CHECK must be a positive integer
注意- 我知道它可以通过@Jav 使用类似的解决方案来实现
dt[, error := lapply(param_names, function(x) {
((get(x, dt) %in% get(x, valid_values))) %>%
ifelse(., " ", paste(x, "should have valid values like -", paste(get(x, valid_values), collapse = " ")))
}) %>% Reduce(paste, .)]
但是,我正在努力ifelse
使用上述解决方案来使用多个条件。我正在寻找有效和清洁的解决方案来避免for loops
。任何其他方法也可以。
解决方案
您可以摆脱嵌套循环,但仍然需要编写大量代码。在我看来,最简洁的方法是编写一个自定义函数来定义如何应用逻辑:
library(tidyverse)
check_col_validity <- function(col, name) {
r_error <- rep(NA, length(col))
# is required?
if (required_list[name] == 1) {
msg <- paste(toupper(name), "is required")
r_error <- ifelse(is.na(col), msg, NA)
}
# is continuous?
if (col_type_list[name] == "continuous") {
msg <- paste(toupper(name), "must be positive")
new_error <- ifelse(col < 0 | is.na(col), msg, NA)
error <- ifelse(is.na(r_error), new_error, paste(r_error, new_error, sep = " & "))
}
# is in valid range?
if (col_type_list[name] == "factor") {
valid_range <- valid_values[[name]]
msg <- paste(toupper(name), "must be one of", paste(valid_range, collapse = ", "))
new_error <- ifelse(col %in% valid_range, NA, msg)
error <- ifelse(is.na(r_error), new_error, r_error)
}
return(error)
}
这很像你的逻辑。不同之处在于它如何应用于数据:
dt$error <- dt[, 1:5] %>%
purrr::imap_dfc(check_col_validity) %>%
t() %>%
as_tibble() %>%
purrr::map_chr(paste, collapse = " & ") %>%
stringr::str_remove_all("NA & ") %>%
stringr::str_remove_all(" & NA")
该函数使用 应用于每一列purrr::imap
。结果被转置并粘贴在一起,之后的最后一步是删除丑陋的 NA 字符串。它提供了预期的结果,我希望代码更清晰。
这个过程的主要部分是如何imap
工作的。它是对列表的应用类型操作,但它将列表元素的名称作为第二个参数传递给函数。这意味着您可以编写一个应用于数据框每一列的自定义函数,并向函数添加第二个参数,该函数imap
将传递列的名称。一旦您在函数中获得了列的数据和名称,该函数就变得更容易编写了。
自定义函数返回适用于该列的错误消息。这意味着您将获得与原始数据集具有相同维度的数据框。然后,您可以转置此数据框并将每列的结果粘贴在一起,以获得每行 1 条消息。
推荐阅读
- html - 车把模板表单/req.body 为多个相同的(第一个){{id}}
- java - 多线程时不随机调用onClick
- php - Laravel 5.8 侦听器事件在服务器上不起作用
- assembly - 使用链接描述文件中的位置计数器会影响哪些内存?
- sql - 运行 sp_depends 系统过程时,如果列“column”为 NULL 是什么意思
- java - java.lang.SecurityException onRequestPermissionsResult
- javascript - 如何避免一个音符覆盖另一个音符?(本地存储)
- python - 从彭博社提取财务数据
- qt - QML TextField 设置焦点突出显示颜色
- linux - 返回提示模式前修改二进制输出