使用R中的第三个变量列表,在多个变量之间进行变异

使用R中的第三个变量列表,在多个变量之间进行变异,r,dplyr,mutate,R,Dplyr,Mutate,我需要获得2016年有效值条件下的成绩列表(数学、语言、sci等)(validity\u 2016==“yes”)的值,并输入一个名为grades{subjects}的新变量(如grades\u math) 结果应该是这样的: df<-tibble(person = c("Alice", "Bob", "Mary"), validity_2016 = c(NA, "yes", NA

我需要获得2016年有效值条件下的成绩列表(数学、语言、sci等)(
validity\u 2016
==“yes”)的值,并输入一个名为
grades{subjects}
的新变量(如grades\u 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),
               grades_math=c(6,5,4),
               grades_language=c(7,6,7),
               grades_sci=c(7,6,9))

df我建议对每个受试者使用
mutate
ifelse
。比如:

df2=df%>%
变异(成绩数学=ifelse(validatiy数学=2016=“是”,成绩数学=2016,成绩数学=2015))
如果这种方法的缺点是你需要对每个主题重复它。这可以通过以下方式实现自动化:

out\u cols=c(“数学成绩”、“科学成绩”)
用于(列输入输出){
c15=0(颜色,“_2015”)
c16=0(col,“_2016”)
df=df%>%突变(!!sym(col):=ifelse(有效性_2016==“是”!!sym(c16),!!sym(c15)))
}
其中
!!sym(x)
将保存在变量
x
中的文本转换为变量名(例如,如果
x=“sci”
!!sym(x)
为我们提供变量
sci
而不是文本
“sci”
或变量
x
)。

tidyverse
示例:
本例使用
mutate
case\u 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

该函数将接受“是”回答并返回当年的值。如果答案为“否”,则它将返回前一年的值。

您好,Andres,您是否可以减少列数?问题越简单,我们回答的速度就越快。事实上,我真正的问题是一个大约有109个变量的数据集,这对我来说不可能减少列数,因为我会失去IssueGod答案的背景。我认为它不像下面这样灵活,因为您必须为每个变量(
col\u names[1:200]
)指定mutate中的参数,并将返回的col\u names括起来?是 啊如果您的用例需要,我可以使用
for循环
使其更加灵活。让我知道模式和缩放用例,我可以更改代码。此外,如果您尝试使用前一年不可用的年份,此函数将对您发出警告。此外,在colnames中使用#s(如validity#u 2016)将对任何未命名validity的列(不包括
grades
列)返回无意义的结果。
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))
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
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