I have a named dataframe containig logicals with missings and I want to get a vector with the column names where values are TRUE
(going down the rows and, if multiple TRUE
s in one row, going from left to right). Here an example:
df <- data.frame(a= c(FALSE, NA, TRUE, TRUE),
b= c(TRUE, FALSE, FALSE, NA),
c= c(TRUE, TRUE, NA, NA))
df
# a b c
# 1 FALSE TRUE TRUE
# 2 NA FALSE TRUE
# 3 TRUE FALSE NA
# 4 TRUE NA NA
expected <- c("b", "c", "c", "a", "a")
Going from first to last row we see TRUE
in the first row. Here are multiple TRUE
s, thus we go from left to right and get "b"
and "c"
. In second tow we get "c"
, and so on.
How to do this (in an elegant way)?
CodePudding user response:
You can do in base
R:
pos <- which(t(df) == TRUE, arr.ind = TRUE)
names(df)[pos[, "row"]]
[1] "b" "c" "c" "a" "a"
CodePudding user response:
You can also try using apply
unlist(apply(df, 1, function(x){na.omit(names(df)[x])}))
[1] "b" "c" "c" "a" "a"
CodePudding user response:
Here is a tidyverse way:
library(dplyr)
library(tidyr)
vector <- df %>%
mutate(across(, ~case_when(.==TRUE ~ cur_column()), .names = 'new_{col}')) %>%
unite(New_Col, starts_with('new'), na.rm = TRUE, sep = ', ') %>%
separate_rows(New_Col) %>%
pull(New_Col)
Or:
library(dplyr)
library(tidyr)
df %>%
mutate(across(, ~case_when(.==TRUE ~ cur_column()))) %>%
pivot_longer(everything()) %>%
na.omit() %>%
pull(value)
[1] "b" "c" "c" "a" "a"
CodePudding user response:
Another possible solution, based on purrr::pmap
:
library(tidyverse)
pmap(df, ~ names(df)[c(...)] %>% na.omit) %>% unlist
#> [1] "b" "c" "c" "a" "a"
CodePudding user response:
You can use %%
(modulo) to identify the column indices.
names(df)[(which(t(df)) - 1) %% ncol(df) 1]
# [1] "b" "c" "c" "a" "a"