繁体   English   中英

如何使用 tidyverse 将列转换为多个 boolean 列

[英]How to convert columns to multiple boolean columns with tidyverse

我每次都有一组列,我想将其转换为许多 boolean 列(按类别),其中mutate()和 cross across()如下所示:

data <- data.frame(category_t1 = c("A","B","C","C","A","B"),
                   category_t2 = c("A","C","B","B","B",NA),
                   category_t3 = c("C","C",NA,"B",NA,"A"))

data %>% mutate(across(starts_with("category"), 
                       ~case_when(.x == "A" ~ TRUE, !is.na(.x) ~ FALSE),
                       .names = "{str_replace(.col, 'category', 'A')}"),
                across(starts_with("category"), 
                       ~case_when(.x == "B" ~ TRUE, !is.na(.x) ~ FALSE),
                       .names = "{str_replace(.col, 'category', 'B')}"),
                across(starts_with("category"), 
                       ~case_when(.x == "C" ~ TRUE, !is.na(.x) ~ FALSE),
                       .names = "{str_replace(.col, 'category', 'C')}"))

这使得:

category_t1 category_t2 category_t3  A_t1  A_t2  A_t3  B_t1  B_t2  B_t3  C_t1  C_t2
1         A           A           C  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE
2         B           C           C FALSE FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE
3         C           B        <NA> FALSE FALSE    NA FALSE  TRUE    NA  TRUE FALSE
4         C           B           B FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE
5         A           B        <NA>  TRUE FALSE    NA FALSE  TRUE    NA FALSE FALSE
6         B        <NA>           A FALSE    NA  TRUE  TRUE    NA FALSE FALSE    NA

它有效,但我想知道是否有更好的主意,因为在这里我执行相同的代码 3 次而不是一个大代码(想象如果我有 10 次重复它......)。 我虽然可以用map()做到这一点,但我没有设法让它工作。 我认为存在问题,因为 cross across()中的.names参数无法与我在case_when()中使用的字符串连接。

我认为在...论点中可能有一些事情要做,例如:

data %>% mutate(across(starts_with("category"),
                       ~case_when(.x == mod ~ TRUE, !is.na(.x) ~ FALSE),
                       mod = levels(as.factor(data$category_t1)),
                       .names = "{str_replace(.col, 'category', mod)}"))

但这当然在这里行不通。 你知道怎么做吗?

非常感谢。

purrrmap_dfc可以与您当前的方法很好地匹配:

library(dplyr)
library(purrr)

bind_cols(data, 
          map_dfc(LETTERS[1:3], \(letter) { mutate(data,
                                                   across(starts_with("category"), 
                                                          ~ case_when(.x == letter ~ TRUE, !is.na(.x) ~ FALSE),
                                                   .names = paste0("{str_replace(.col, 'category', '", letter, "')}")),
                                                   .keep = "none") }
                  )
          )

或者跳过bind_cols并使用.keep = ifelse(letter == "A", "all", "none")

Output:

  category_t1 category_t2 category_t3  A_t1  A_t2  A_t3  B_t1  B_t2  B_t3  C_t1  C_t2  C_t3
1           A           A           C  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE
2           B           C           C FALSE FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE  TRUE
3           C           B        <NA> FALSE FALSE    NA FALSE  TRUE    NA  TRUE FALSE    NA
4           C           B           B FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE
5           A           B        <NA>  TRUE FALSE    NA FALSE  TRUE    NA FALSE FALSE    NA
6           B        <NA>           A FALSE    NA  TRUE  TRUE    NA FALSE FALSE    NA FALSE

不是一个tidyverse选项(尽管管道兼容),它很容易使用 package fastDummies

fastDummies::dummy_cols(data, ignore_na = TRUE)
  category_t1 category_t2 category_t3 category_t1_A category_t1_B category_t1_C category_t2_A category_t2_B category_t2_C category_t3_A category_t3_B category_t3_C
1           A           A           C             1             0             0             1             0             0             0             0             1
2           B           C           C             0             1             0             0             0             1             0             0             1
3           C           B        <NA>             0             0             1             0             1             0            NA            NA            NA
4           C           B           B             0             0             1             0             1             0             0             1             0
5           A           B        <NA>             1             0             0             0             1             0            NA            NA            NA
6           B        <NA>           A             0             1             0            NA            NA            NA             1             0             0

具有嵌套lapply()base解决方案:

cbind(data, lapply(data, \(x) {
  lev <- levels(factor(x))
  sapply(setNames(lev, lev), \(y) x == y)
}))

  category_t1 category_t2 category_t3 category_t1.A category_t1.B category_t1.C category_t2.A category_t2.B category_t2.C category_t3.A category_t3.B category_t3.C
1           A           A           C          TRUE         FALSE         FALSE          TRUE         FALSE         FALSE         FALSE         FALSE          TRUE
2           B           C           C         FALSE          TRUE         FALSE         FALSE         FALSE          TRUE         FALSE         FALSE          TRUE
3           C           B        <NA>         FALSE         FALSE          TRUE         FALSE          TRUE         FALSE            NA            NA            NA
4           C           B           B         FALSE         FALSE          TRUE         FALSE          TRUE         FALSE         FALSE          TRUE         FALSE
5           A           B        <NA>          TRUE         FALSE         FALSE         FALSE          TRUE         FALSE            NA            NA            NA
6           B        <NA>           A         FALSE          TRUE         FALSE            NA            NA            NA          TRUE         FALSE         FALSE

我们可以使用来自base R model.matrix model.matrix

m1 <- model.matrix( ~ 0 + ., replace(data, is.na(data), "NA"))> 0
cbind(data, m1[,-ncol(m1)])

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM