Lul*_*ulY 3 r logical-operators dataframe rowwise
我有一个包含多个列的数据框,其中包含一个诊断的信息。条目是TRUE,FALSE或NA。我创建了一个向量,将这些列总结如下:如果患者在某个时间 ( TRUE) 被诊断出来,则TRUE,如果唯一有效的条目是FALSE,则FALSE,如果只是缺失,则NA。将文本写成代码:
data.frame(a= c(FALSE, TRUE, NA, FALSE, TRUE, NA, FALSE, TRUE, NA),
b= c(FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, NA, NA, NA),
expected= c(FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, NA))
Run Code Online (Sandbox Code Playgroud)
我需要按行遍历所有列,并且使用split. 不幸的是,我的数据很大,需要很长时间。我现在所做的是
library(magrittr)
# big example data
df <- expand.grid(c(FALSE, TRUE, NA), c(FALSE, TRUE, NA)) %>%
.[rep(1:nrow(.), 50000), ] %>%
as.data.frame() %>%
setNames(., nm= c("a", "b"))
# My approach
df$res <- df %>%
split(., 1:nrow(.)) %>%
lapply(., function(row_i){
ifelse(all(is.na(row_i)), NA,
ifelse(any(row_i, na.rm= TRUE), TRUE,
ifelse(any(!row_i, na.rm= TRUE), FALSE,
row_i)))
}) %>%
unlist()
Run Code Online (Sandbox Code Playgroud)
有没有更有效的方法来解决这个任务?
使用以下方法的矢量化解决方案pmax():
df$result <- as.logical(do.call(\(...) pmax(..., na.rm = TRUE), df[1:2]))
df
# a b expected result
# 1 FALSE FALSE FALSE FALSE
# 2 TRUE FALSE TRUE TRUE
# 3 NA FALSE FALSE FALSE
# 4 FALSE TRUE TRUE TRUE
# 5 TRUE TRUE TRUE TRUE
# 6 NA TRUE TRUE TRUE
# 7 FALSE NA FALSE FALSE
# 8 TRUE NA TRUE TRUE
# 9 NA NA NA NA
Run Code Online (Sandbox Code Playgroud)
您还可以将所有参数合并到一个列表中,以避免do.call(). 我将其重写为一个函数rowAnys来补充rowSums/rowMeans中的base。
rowAnys <- function(x) {
as.logical(do.call(pmax, c(na.rm = TRUE, x)))
}
Run Code Online (Sandbox Code Playgroud)
您还可以用来pmin实现 rowwise- all()。
rowAlls <- function(x) {
as.logical(do.call(pmin, c(na.rm = TRUE, x)))
}
Run Code Online (Sandbox Code Playgroud)
df$any <- rowAnys(df[1:2])
df$all <- rowAlls(df[1:2])
df
# a b expected any all
# 1 FALSE FALSE FALSE FALSE FALSE
# 2 TRUE FALSE TRUE TRUE FALSE
# 3 NA FALSE FALSE FALSE FALSE
# 4 FALSE TRUE TRUE TRUE FALSE
# 5 TRUE TRUE TRUE TRUE TRUE
# 6 NA TRUE TRUE TRUE TRUE
# 7 FALSE NA FALSE FALSE FALSE
# 8 TRUE NA TRUE TRUE TRUE
# 9 NA NA NA NA NA
Run Code Online (Sandbox Code Playgroud)
一种选择是使用case_when()dplyr 包中的矢量化函数(https://dplyr.tidyverse.org/reference/case_when.html),例如
library(dplyr)
df <- expand.grid(c(FALSE, TRUE, NA), c(FALSE, TRUE, NA)) %>%
.[rep(1:nrow(.), 50000), ] %>%
as.data.frame() %>%
setNames(., nm= c("a", "b"))
df$res <- df %>%
split(., 1:nrow(.)) %>%
lapply(., function(row_i){
ifelse(all(is.na(row_i)), NA,
ifelse(any(row_i, na.rm= TRUE), TRUE,
ifelse(any(!row_i, na.rm= TRUE), FALSE,
row_i)))
}) %>%
unlist()
current_output <- df
# load 'clean' example data
df <- expand.grid(c(FALSE, TRUE, NA), c(FALSE, TRUE, NA)) %>%
.[rep(1:nrow(.), 50000), ] %>%
as.data.frame() %>%
setNames(., nm= c("a", "b"))
case_when_output <- df %>%
mutate(res = case_when(if_any(everything(), ~.x == TRUE) ~ TRUE,
if_all(everything(), ~is.na(.x)) ~ NA,
TRUE ~ FALSE))
all.equal(current_output, case_when_output)
#> [1] TRUE
Run Code Online (Sandbox Code Playgroud)
创建于 2023-07-18,使用reprex v2.0.2
基准测试(6yo core-i5 macbook pro;更新于 2023 年 7 月 20 日):
library(dplyr)
# install.packages("purrrlyr")
library(purrrlyr)
library(microbenchmark)
library(ggplot2)
df <- expand.grid(c(FALSE, TRUE, NA), c(FALSE, TRUE, NA)) %>%
.[rep(1:nrow(.), 50000), ] %>%
as.data.frame() %>%
setNames(., nm= c("a", "b"))
ingo_pingo_func <- function(df) {
df$res <- df %>%
split(., 1:nrow(.)) %>%
lapply(., function(row_i){
ifelse(all(is.na(row_i)), NA,
ifelse(any(row_i, na.rm= TRUE), TRUE,
ifelse(any(!row_i, na.rm= TRUE), FALSE,
row_i)))
}) %>%
unlist()
}
jared_mamrot_func <- function(df) {
case_when_output <- df %>%
mutate(res = case_when(if_any(1:2, ~.x == TRUE) ~ TRUE,
if_all(1:2, ~is.na(.x)) ~ NA,
TRUE ~ FALSE))
}
darren_tsai_func <- function(df) {
df$result <- as.logical(do.call(\(...) pmax(..., na.rm = TRUE), df[1:2]))
}
roland_func <- function(df) {
cols <- 1:2
df$result <- Reduce(\(x, y) x | y, df[cols])
df[is.na(df$result), "result"] <- Reduce(\(x, y) ifelse(!is.na(x) | !is.na(y), FALSE, NA),
df[is.na(df$result), cols])
}
yuriy_saraykin_func <- function(df) {
whereNA <- rowSums(is.na(df)) == ncol(df)
df$expected <- rowSums(df, na.rm = TRUE) > 0
df$expected[whereNA] <- NA
}
efz_func <- function(df) {
output <- df %>% by_row(..f=function(row_i){
ifelse(all(is.na(row_i)), NA,
ifelse(any(row_i, na.rm= TRUE), TRUE,
ifelse(any(!row_i, na.rm= TRUE), FALSE,
row_i)))
}, .collate = 'rows')
}
TIC_func <- function(df) {
df$result <- rowSums(df, na.rm = TRUE) > 0 * NA^(rowMeans(is.na(df)) == 1)
}
result <- microbenchmark(ingo_pingo_func(df),
jared_mamrot_func(df),
darren_tsai_func(df),
roland_func(df),
yuriy_saraykin_func(df),
efz_func(df),
TIC_func(df),
times = 5)
result$expr <- forcats::fct_rev(forcats::fct_reorder(result$expr, result$time, mean))
autoplot(result)
Run Code Online (Sandbox Code Playgroud)