【问题标题】:Mutate over every possible combination of columns对所有可能的列组合进行变异
【发布时间】:2018-07-26 21:16:13
【问题描述】:

我有一个二进制变量的数据框:

df <-data.frame(a = c(0,1,0,1,0), b = c(1, 1, 0, 0, 1), c = c(1,0,1,1,0))

我想为我预先存在的列的每个可能组合创建一个列:

library(tidyverse)
df %>% 
mutate(d = case_when(a==1 & b==1 & c==1 ~ 1),
             e = case_when(a==1 & b==1 & c!=1 ~ 1),
             f = case_when(a==1 & b!=1 & c==1 ~ 1),
             g = case_when(a!=1 & b==1 & c==1 ~ 1))

但我的真实数据集有太多列,无法在没有函数或循环的情况下执行此操作。有没有一种简单的方法可以在 R 中做到这一点?

【问题讨论】:

  • 你想给新列什么样的标签?例如。按字母顺序?

标签: r loops dplyr


【解决方案1】:

大卫的答案的替代方案,但我承认这有点尴尬:

df %>% 
 unite(comb, a:c, remove = FALSE) %>% 
 spread(key = comb, value = comb) %>% 
 mutate_if(is.character, funs(if_else(is.na(.), 0, 1)))

#>   a b c 0_0_1 0_1_0 0_1_1 1_0_1 1_1_0
#> 1 0 0 1     1     0     0     0     0
#> 2 0 1 0     0     1     0     0     0
#> 3 0 1 1     0     0     1     0     0
#> 4 1 0 1     0     0     0     1     0
#> 5 1 1 0     0     0     0     0     1

编辑:funs()dplyr 的 0.8.0 版起已弃用,因此最后一行应修改为:

mutate_if(is.character, list(~ if_else(is.na(.), 0, 1)))

【讨论】:

    【解决方案2】:

    首先请注意,do.call(paste0, df) 会将您的所有列组合成一个字符串,无论它们有多少:

    do.call(paste0, df)
    # [1] "011" "110" "001" "101" "010" "011"
    

    然后,您可以使用 tidyr 包中的 spread() 为每个列提供自己的列。请注意,您必须添加一个额外的 row 列,以便它知道将每一行分开(而不是尝试将它们组合起来)。

    # I added a sixth row that copied the first to make the effect clear
    df<-data.frame(a = c(0,1,0,1,0,0), b = c(1, 1, 0, 0, 1, 1), c = c(1,0,1,1,0,1))
    
    # this assumes you want `type_` at the start of each new column,
    # but you could use a different convention
    df %>%
      mutate(type = paste0("type_", do.call(paste0, df)),
             value = 1,
             row = row_number()) %>%
      spread(type, value, fill = 0) %>%
      select(-row)
    

    结果:

      a b c type_001 type_010 type_011 type_101 type_110
    1 0 0 1        1        0        0        0        0
    2 0 1 0        0        1        0        0        0
    3 0 1 1        0        0        1        0        0
    4 0 1 1        0        0        1        0        0
    5 1 0 1        0        0        0        1        0
    6 1 1 0        0        0        0        0        1
    

    【讨论】:

    • 基本 R 中的类似逻辑 type_ &lt;- interaction(df[1:3]); cbind(df[1:3], model.matrix(~ type_ + 0))
    • @thelatemail 不错!为什么是 [1:3]?
    • 因为df 中可能有其他列您不想参与interaction 计算。根据需要的输出,可能会从cbind() 调用中删除它。
    • 需要注意的是,使用paste 并不能说明所有可能的组合,如果碰巧有没有表示出来的组合。
    • 您可以以tidyr::expand() 开头来捕获所有可能的组合,但您需要手动列出所有列。如果要列出很多列,那会很烦人。
    猜你喜欢
    • 1970-01-01
    • 2015-05-13
    • 1970-01-01
    • 2017-01-22
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 2014-06-06
    • 1970-01-01
    相关资源
    最近更新 更多