【问题标题】:How to conditionally mutate a variable in R based on the values in multiple columns?如何根据多列中的值有条件地改变 R 中的变量?
【发布时间】:2021-10-15 04:57:07
【问题描述】:

最近没有使用当前 tidyverse 动词(在我的例子中为 R 4.1 和 tidyverse 1.3.1)来回答这个问题。我尝试将 mutate 与 case_when() 和 ifelse() 与 select_if() 一起使用,以有条件地用一个从特定其他列中的 TRUE 值的数量逐行计算的值填充新变量,但似乎都没有过滤正确的列按预期计算。我可能会旋转更长的时间来替换我的列分组,并避免需要过滤哪些列用于变异计算,但我希望每行保留一个响应以供以后合并。这是一个可重现的示例。

library(tidyverse)
set.seed(195)

# create dataframe
response_id <- rep(1:461)
questions <- c("overall","drought","domestic","livestock","distance")
answers <- c("a","b","c","d","e")
colnames <- apply(expand.grid(questions, answers), 1, paste, collapse="_")
df <- tibble(response_id)
# data is actually an unknown mix of TRUE and FALSE values in all columns but just doing that for one column for now for simplicity
df[,colnames] = FALSE
df$overall_a[sample(nrow(df),100)] <- TRUE

# using ifelse and select if to filter which columns to sum
df %>%
 mutate(positive = ifelse(select_if(isTRUE), sum(str_detect(colnames(df), "a|b")), NA)) %>%
 mutate(negative = ifelse(select_if(isTRUE), sum(str_detect(colnames(df), "c|d|e")), NA)) %>%
 select(response_id, positive, negative)

# using case_when
df %>%
 mutate(positive = case_when(TRUE ~ sum(str_detect(colnames(df), "a|b"))), NA) %>%
 mutate(negative = case_when(TRUE ~ sum(str_detect(colnames(df), "c|d|e"))), NA) %>%
 select(response_id, positive, negative)

所需的输出应如下所示。感谢您对此的任何帮助!

# A tibble: 461 × 3
   response_id positive negative
         <int>    <int>    <int>
 1           1       0       0
 2           2       0       0
 3           3       0       0
 4           4       0       0
 5           5       1       0
 6           6       1       0
 7           7       0       0
 8           8       1       0
 9           9       0       0
10          10       1       0
# … with 451 more rows

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    在列名中包含数据不被认为是“整洁的”,而“tidyverse”最适用于整洁的数据。与 tidy 理念最一致的方法是旋转方法,而不是对列名进行黑客攻击。此外,它将更好地扩展到更多类别。例如

    df %>% 
      pivot_longer(-response_id) %>% 
      separate(name, into=c("category", "code")) %>% 
      mutate(sentiment=case_when(
        code %in% c("a", "b") ~ "positive", 
        code %in% c("c", "d", "e") ~ "negative")) %>% 
      group_by(response_id, sentiment) %>% 
      summarize(count=sum(value)) %>% 
      pivot_wider(response_id, names_from=sentiment, values_from=count)
    

    它没有那么简洁,但它更直接地说明了它在做什么。

    但如果你真的想将数据保留在行名中,你可以使用c_across() 和最新的 dplyr 执行逐行汇总

    df %>% 
      rowwise() %>% 
      mutate(
        positive=sum(c_across(ends_with(c("_a", "_b")))),
        negative=sum(c_across(ends_with(c("_c", "_d", "_e"))))) %>% 
      select(response_id, positive, negative)
    

    【讨论】:

    • 谢谢 - 旋转两次总是让我绊倒,但这很好用,我同意更整洁的方法更适合应用于我的数据集。
    • 解释得很好?
    猜你喜欢
    • 2020-04-24
    • 1970-01-01
    • 2020-02-18
    • 2021-07-03
    • 2023-02-09
    • 1970-01-01
    • 2015-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多