#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