масштабируемый случай_когда случай, объединяющий любые две ситуации

#r #dplyr

Вопрос:

Я ищу масштабируемую версию следующего.

Дано:

 library(tidyverse) df lt;- data.frame(a = c(1, 2, 3, 4, 5, 3, 1),  b = c(6, 7, 8, 9, 10, 8, 9),  c = c(15, 12, 9, 2, 13, 9, 10)) df # a b c # 1 1 6 15 # 2 2 7 12 # 3 3 8 9 # 4 4 9 2 # 5 5 10 13 # 6 3 8 9 # 7 1 9 10  

Я хочу создать переменную индикатора, если допустимы любые две комбинации следующих критериев:

a gt; 3, b gt;gt; 8, c gt;gt;gt; 10

Один из вариантов сделать это вручную-использовать case_when :

 df %gt;%   mutate(indicator_variable = case_when(  a gt; 3 amp; b gt; 8 ~ 1,  a gt; 3 amp; c gt; 10 ~ 1,  b gt; 8 amp; c gt; 10 ~ 1,  TRUE ~ 0  ))  # a b c indicator_variable # 1 1 6 15 0 # 2 2 7 12 0 # 3 3 8 9 0 # 4 4 9 2 1 # 5 5 10 13 1 # 6 3 8 9 0 # 7 1 9 10 0  

Это работает, но, очевидно, становится сложнее, чем больше переменных рассматривается ( choose(4, 2) ), измените критерии на любые две из четырех переменных:

a gt; 3, b gt;gt; 8, c gt;gt;gt; 10, d gt;gt;gt;gt;= 5

 df2 lt;- data.frame(a = c(1, 2, 3, 4, 5, 3, 1),  b = c(6, 7, 8, 9, 10, 8, 9),  c = c(15, 12, 9, 2, 13, 9, 10),  d = c(1, 2, 3, 4, 5, 6, 5)) df2 # a b c d # 1 1 6 15 1 # 2 2 7 12 2 # 3 3 8 9 3 # 4 4 9 2 4 # 5 5 10 13 5 # 6 3 8 9 6 # 7 1 9 10 5  df2 %gt;%   mutate(indicator_variable = case_when(  a gt; 3 amp; b gt; 8 ~ 1,  a gt; 3 amp; c gt; 10 ~ 1,  a gt; 3 amp; d gt;= 5 ~ 1,  b gt; 8 amp; c gt; 10 ~ 1,  b gt; 8 amp; d gt;= 5 ~ 1,  c gt; 10 amp; d gt;= 5 ~ 1,  TRUE ~ 0  )) # a b c d indicator_variable # 1 1 6 15 1 0 # 2 2 7 12 2 0 # 3 3 8 9 3 0 # 4 4 9 2 4 1 # 5 5 10 13 5 1 # 6 3 8 9 6 0 # 7 1 9 10 5 1  

и т.д.

Лучшие подходы? Не обязательно вовлекать case_when , может combn быть, можно было бы использовать?

Спасибо

Ответ №1:

Не нужно использовать case_when здесь, просто используйте тот факт, что TRUE преобразуется в 1 в арифметических операциях и FALSE в 0 .

 library(dplyr) df lt;- tibble(a = c(1, 2, 3, 4, 5, 3, 1),  b = c(6, 7, 8, 9, 10, 8, 9),  c = c(15, 12, 9, 2, 13, 9, 10)) df %gt;%  mutate(indicator = as.numeric(((a gt; 3)   (b gt; 8)   (c gt; 10)) gt;= 2)) #gt; # A tibble: 7 × 4 #gt; a b c indicator #gt; lt;dblgt; lt;dblgt; lt;dblgt; lt;dblgt; #gt; 1 1 6 15 0 #gt; 2 2 7 12 0 #gt; 3 3 8 9 0 #gt; 4 4 9 2 1 #gt; 5 5 10 13 1 #gt; 6 3 8 9 0 #gt; 7 1 9 10 0  

Ответ №2:

Создайте функцию, которая принимает входные данные для оператора, значения и набора данных

 f1 lt;- function(dat, val, op) op(dat, val)  

Затем создайте два list s` со значениями и оператором (если операторы одинаковы, нам это не нужно).

 lst1 lt;- list(a = 3, b = 8, c = 10, d = 5) lst2 lt;- list(a = `gt;`, b = `gt;`, c = `gt;`, d = `gt;=`)  

Теперь мы делаем combn с Reduce (используя вторые данные «df2»)

 df2$indicator_variable lt;-  (Reduce(`|`, combn(lst1, 2, function(x)   Reduce(`amp;`, Map(f1, dat = df2[names(x)], val = lst1[names(x)],   op = lst2[names(x)])), simplify = FALSE)))  

-выход

 gt; df2  a b c d indicator_variable 1 1 6 15 1 0 2 2 7 12 2 0 3 3 8 9 3 0 4 4 9 2 4 1 5 5 10 13 5 1 6 3 8 9 6 0 7 1 9 10 5 1  

Или если мы хотим обновить первые данные

 lst1 lt;- list(a = 3, b = 8, c = 10) lst2 lt;- list(a = `gt;`, b = `gt;`, c = `gt;`) df$indicator_variable lt;-  (Reduce(`|`, combn(lst1, 2, function(x)   Reduce(`amp;`, Map(f1, dat = df[names(x)], val = lst1[names(x)],   op = lst2[names(x)])), simplify = FALSE))) gt; df  a b c indicator_variable 1 1 6 15 0 2 2 7 12 0 3 3 8 9 0 4 4 9 2 1 5 5 10 13 1 6 3 8 9 0 7 1 9 10 0