Функция R для выявления случаев, когда условие выполняется x раз в любом из n столбцов?

У меня есть фрейм данных, в котором я хотел бы определить случаи (строки), в которых заданное условие выполняется как минимум определенное количество раз в наборе столбцов. В приведенном ниже игрушечном примере я хотел бы определить случаи, когда «А» — это выбор для двух из трех столбцов (от «Выбор_1» до «Выбор_3»). Мне все равно, в каких двух из трех столбцов находится «А». В моем примере будут идентифицированы ID = 1 и ID = 4.

Это должно работать с любым желаемым количеством «A» в любом количестве столбцов (например, если бы я хотел определить случаи, когда «A» является выбором в трех из четырех столбцов «Выбор», будет идентифицирован только ID = 1).

ID <- 1:4
Choice_1 <- c("A", "B", "C", "D")
Choice_2 <- c("A", "D", "C", "A")
Choice_3 <- c("A", "C", "A", "A")
Choice_4 <- c("B", "B", "A", "B")

df <- data.frame(ID, Choice_1, Choice_2, Choice_3, Choice_4)

> df
ID Choice_1 Choice_2 Choice_3 Choice_4
 1        A        A        A        B
 2        B        D        C        B
 3        C        C        A        A
 4        D        A        A        B

Одним из окольных способов сделать это было бы преобразовать «A» в 1, а все остальное в 0, просуммировать интересующие меня столбцы «Выбор» и проверить, что сумма равна или превышает мой порог, но я чувствую, что должен быть лучшим способом.

Как я себе это представляю, это будет какая-то форма оператора if_else, включенного в мутацию, чтобы строки, соответствующие условию, были идентифицированы с 1, а те, которые не соответствуют 0:

df %>% mutate(cond_matched = if_else( two of (Choice_1, Choice_2, Choice_3) == "A", 1, 0))

ID Choice_1 Choice_2 Choice_3 Choice_4 cond_matched
 1        A        A        A        B            1
 2        B        D        C        B            0
 3        C        C        A        A            0
 4        D        A        A        B            1

Я надеюсь, что я только что искал с неправильными ключевыми словами. Спасибо за любую помощь!

Почему ID 3 получает 0?

Jon Spring 29.05.2019 22:29

@Jon Spring, потому что я тестирую только Choice_1 - Choice_3.

lcabral 30.05.2019 08:03
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
209
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Базовый вариант R будет состоять в том, чтобы создать логическую матрицу из выбранных столбцов (df[2:4] == "A"), получить построчную сумму ИСТИННЫХ элементов и проверить, больше ли она или равна 2, привести логический вектор к двоичному с помощью as.integer или + (хаки)

df$cond_matched <- +(rowSums(df[2:4] == "A") >= 2)
df$cond_matched
#[1] 1 0 0 1

Или с помощью tidyverse (с аналогичной логикой из базового решения R, но не совсем с таким же синтаксисом)

library(tidyverse)
df %>% 
    mutate(cond_matched = select(., 2:4) %>%
                            map(~ .x == 'A') %>%
                            reduce(`+`) %>%
                            `>=`(2) %>% 
                            as.integer)
#   ID Choice_1 Choice_2 Choice_3 Choice_4 cond_matched
#1  1        A        A        A        B            1
#2  2        B        D        C        B            0
#3  3        C        C        A        A            0
#4  4        D        A        A        B            1

Спасибо @akrun! Base R кажется намного проще ... Мне нужно будет изучить, что карта и сокращение делают в решении tidyverse, мне никогда не приходилось использовать их в прошлом.

lcabral 30.05.2019 08:16

Одна из возможностей dplyr и tidyr может быть:

df %>%
 gather(var, val, -c(ID, Choice_4)) %>%
 group_by(ID) %>%
 summarise(cond_matched = as.integer(sum(val == "A") >= 2)) %>%
 ungroup() %>%
 left_join(df, by = c("ID" = "ID"))

     ID cond_matched Choice_1 Choice_2 Choice_3 Choice_4
  <int>        <int> <chr>    <chr>    <chr>    <chr>   
1     1            1 A        A        A        B       
2     2            0 B        D        C        B       
3     3            0 C        C        A        A       
4     4            1 D        A        A        B  

Или просто с dplyr (используя в основном ту же логику, что и @akrun):

df %>%
 mutate(cond_matched = as.integer(rowSums(.[-ncol(.)] == "A") >= 2))

Чтобы явно назвать столбцы:

df %>%
 mutate(cond_matched = as.integer(rowSums(.[grepl("Choice_1|Choice_2|Choice_3", colnames(.))] == "A") >= 2))

Спасибо! Просто чтобы уточнить, я думаю, вы использовали -ncol(.), чтобы избавиться от Choice_4. Каким был бы синтаксис, если бы я хотел явно назвать Choice_1, Choice_2 и Choice_3? В моем реальном фрейме данных это будет три столбца из 150+, поэтому проще всего использовать имя столбца.

lcabral 30.05.2019 08:14

Другие вопросы по теме