Преобразуйте несколько переменных, используя список третьих переменных в R - PullRequest
3 голосов
/ 06 августа 2020

Мне нужно получить значения списка оценок (математика, язык, наука, и т. Д. c.) При условии наличия действительных значений в 2016 году (validity_2016 == «да») в новую переменную называется grades_{subjects} (например, grades_math).

df<-tibble(person = c("Alice", "Bob", "Mary"),
           validity_2016 = c(NA, "yes", NA),
           likes_ham = c("no", "yes", "yes"),
           grades_math_2015=c(6,2,4),
           grades_math_2016=c(3,5,7),
           grades_language_2015=c(7,1,9),
           grades_language_2016=c(3,6,7),
           grades_sci_2015=c(7,1,9),
           grades_sci_2016=c(3,6,7))

Мне было интересно, можно ли использовать dplyr s mutate_at или mutate(across следующим образом:

dplyr::mutate(across(grades_math_2016, grades_language_2016,grades_sci_2016),
~dplyr::case_when(!is.na(validity_2016)~list(grades_math_2015,grades_language_2015,grades_sci_2015)~.),
.names="{col}"))

Результат должен выглядеть так:

df<-tibble(person = c("Alice", "Bob", "Mary"),
               validity_2016 = c(NA, "yes", NA),
               likes_ham = c("no", "yes", "yes"),
               grades_math_2015=c(6,2,4),
               grades_math_2016=c(3,5,7),
               grades_language_2015=c(7,1,9),
               grades_language_2016=c(3,6,7),
               grades_sci_2015=c(7,1,9),
               grades_sci_2016=c(3,6,7),
               grades_math=c(6,5,4),
               grades_language=c(7,6,7),
               grades_sci=c(7,6,9))

Ответы [ 2 ]

3 голосов
/ 06 августа 2020

Я бы рекомендовал использовать mutate и ifelse для каждого предмета. Что-то вроде:

df2 = df %>%
  mutate(grades_math = ifelse(validatiy_2016 == "yes", grades_math_2016, grades_math_2015))

Обратной стороной этого подхода является то, что вам нужно повторять его для каждого предмета. Это можно автоматизировать с помощью чего-то вроде:

out_cols = c("grades_math", "grades_sci")

for(col in out_cols){
  c15 = paste0(col,"_2015")
  c16 = paste0(col,"_2016")
  df = df %>% mutate(!!sym(col) := ifelse(validaity_2016 == "yes", !!sym(c16), !!sym(c15)))
}

Где !!sym(x) берет текст, сохраненный в переменной x, и превращает его в имя переменной (например, если x = "sci", то !!sym(x) дает нам переменная sci вместо текста "sci" или переменная x).

2 голосов
/ 07 августа 2020

tidyverse и rlang пример:

В этом примере используются mutate и case_when для назначения переменных, как вы описали. Я обернул его функцией на случай, если вы будете делать это часто.

library(tidyverse)
library(rlang)

make_grade_columns <- function(df, condition_col, year_view){
  year_column_names <- colnames(df)[str_detect(colnames(df), year_view) & colnames(df) != condition_col & !str_detect(colnames(df), "validity")]
  year_prior_column_names <- colnames(df)[str_detect(colnames(df), as.character(as.numeric(year_view) - 1)) & colnames(df) != condition_col]
  return_col_names <- str_remove(year_column_names, "_\\d\\d\\d\\d")
  df <- df  %>% mutate(
    !!return_col_names[1] := case_when(
      (df %>% select(!!!condition_col)) == "yes" ~ !! sym(year_column_names[1]),
                                               T ~ !! sym(year_prior_column_names[1])),
    !!return_col_names[2] := case_when(
      (df %>% select(!!!condition_col)) == "yes" ~ !! sym(year_column_names[2]),
                                               T ~ !! sym(year_prior_column_names[2])),
    !!return_col_names[3] := case_when(
      (df %>% select(!!!condition_col)) == "yes" ~ !! sym(year_column_names[3]),
                                               T ~ !! sym(year_prior_column_names[3])))
  
  return(df)
}

make_grade_columns(df, "validity_2016", "2016") %>% 
 select(person, validity_2016, grades_math, grades_sci, grades_language) 

# # A tibble: 3 x 5
# person validity_2016    grades_math   grades_sci   grades_language
# <chr>  <chr>                  <dbl>      <dbl>           <dbl>
# 1 Alice  NA                      6          7               7
# 2 Bob    yes                     5          6               6
# 3 Mary   NA                      4          9               9

Предположим, вы изменили его и хотите увидеть оценки в том случае, если они ответят «да» на likes_ham. Просто используйте это в качестве столбца условий для функции.

make_grade_columns(df, "likes_ham", "2016")%>% 
  select(person, likes_ham, grades_math, grades_sci, grades_language) 
# # A tibble: 3 x 5
# person likes_ham    grades_math grades_sci grades_language
# <chr>  <chr>              <dbl>      <dbl>           <dbl>
# 1 Alice  no                  6          7               7
# 2 Bob    yes                 5          6               6
# 3 Mary   yes                 7          7               7

Функция примет ответ «да» и вернет значения за год. Если ответ отрицательный, то вместо этого будет возвращено значение за предыдущий год.

...