如何使用 mutate 在嵌套 for 循环中创建新变量?

问题描述 投票:0回答:2

我有一个具有唯一 Participant_ID 的数据集,每个 Participant_ID 均由两个不同的 Rater_ID 对许多不同变量进行评分(此处为 Q1、Q2 和 Q3)。我正在尝试找到一种方法来计算一个变量,该变量指示两个评分者的评分是否相差在 1 分之内。这是我正在使用的数据的简化版本:

library(tidyverse)

Participant_ID <- rep(1:3,2)
Rater_ID <- c(rep("A",3),rep("B",3))
Q1 <- c(5, 2, 1,3, 3, 4)
Q2 <- c(4, 2, 2,3, 5, 2)
Q3 <- c(4, 3, 3,3, 4, 5)

df <- tibble(Participant_ID, Rater_ID, Q1, Q2, Q3)

我可以通过使用以下内容拼写出代码的每次迭代来做到这一点:

df <- df %>% group_by(Participant_ID) %>%   
mutate(Check_Q1= ifelse((abs(Q1[1]-Q1[2]) > 1), 1, 0),          
Check_Q2= ifelse((abs(Q2[1]-Q2[2]) > 1), 1, 0),          
Check_Q3= ifelse((abs(Q3[1]-Q3[2]) > 1), 1, 0)) %>% ungroup()

Q1 被标记为参与者 1(分配为 1),Q2 被标记为参与者 2,Q1 和 Q3 都被标记为参与者 3,因为评级差异 > 1。

然而,在我的真实数据中,“Q”变量不仅有3个,还有很多。另外,我希望这段代码能够在 Q 变量数量发生变化的各种情况下使用。用户将在运行代码之前指定问题数。我一直试图弄清楚如何使用 for 循环来做到这一点,但我无法弄清楚。据我所知,这是:

number_of_questions <- 3
questions <- grep("Q", names(df), value=TRUE)

df <-  df %>% group_by(Participant_ID)

for(q in questions){
for(x in 1:number_of_questions){

    check_varname <- paste0("Check_Q",x)
    
    df <- df %>% 
      mutate(!!check_varname := ifelse((abs(get(q)[1]-get(q)[2]) > 1), 1, 0))   
}}

df <-  df %>% ungroup()

我没有收到任何错误,但输出不正确。它为 Participant_ID 3 的 Q1、Q2 和 Q3 分配 1。任何人都可以帮助我理解我做错了什么吗?

r for-loop mutate
2个回答
3
投票

您可以使用

across
.names
函数来完成此操作。

df %>%
  mutate(across(starts_with("Q"), ~ +(abs(.[1] - .[2]) > 1), # thanks @r2evans for improved code
                .names = "Check_{.col}"), .by = Participant_ID)

输出:

  Participant_ID Rater_ID    Q1    Q2    Q3 Check_Q1 Check_Q2 Check_Q3
           <int> <chr>    <dbl> <dbl> <dbl>    <dbl>    <dbl>    <dbl>
1              1 A            5     4     4        1        0        0
2              2 A            2     2     3        0        1        0
3              3 A            1     2     3        1        0        1
4              1 B            3     3     3        1        0        0
5              2 B            3     5     4        0        1        0
6              3 B            4     2     5        1        0        1

(请注意,我假设所有问题都以“Q”开头。如果情况并非如此,您可以使用

across(all_of(2:4), ...)
等内容轻松修改第 2 列到第 4 列)


1
投票

重塑数据可能会更有效和/或更具可读性,以便每个问题都位于行上,评分者位于列上:

df_long <- df %>% 
  pivot_longer(-c(Participant_ID, Rater_ID)) %>% 
  pivot_wider(names_from = Rater_ID, values_from = value)

  Participant_ID name      A     B
           <int> <chr> <dbl> <dbl>
1              1 Q1        5     3
2              1 Q2        4     3
3              1 Q3        4     3
4              2 Q1        2     3
5              2 Q2        2     5
6              2 Q3        3     4
7              3 Q1        1     4
8              3 Q2        2     2
9              3 Q3        3     5

从那里,可以轻松创建检查列:

df_long %>% 
  mutate(check = abs(A - B) > 1)

  Participant_ID name      A     B check
           <int> <chr> <dbl> <dbl> <lgl>
1              1 Q1        5     3 TRUE 
2              1 Q2        4     3 FALSE
3              1 Q3        4     3 FALSE
4              2 Q1        2     3 FALSE
5              2 Q2        2     5 TRUE 
6              2 Q3        3     4 FALSE
7              3 Q1        1     4 TRUE 
8              3 Q2        2     2 FALSE
9              3 Q3        3     5 TRUE 

这可以转变为更广泛的格式:

df_long %>% 
  mutate(check = abs(A - B) > 1) %>% 
  select(-c(A, B)) %>% 
  pivot_wider(names_from = name, values_from = check, names_prefix = 'check_')

  Participant_ID check_Q1 check_Q2 check_Q3
           <int> <lgl>    <lgl>    <lgl>   
1              1 TRUE     FALSE    FALSE   
2              2 FALSE    TRUE     FALSE   
3              3 TRUE     FALSE    TRUE    
© www.soinside.com 2019 - 2024. All rights reserved.