【问题标题】:将 one-hot 编码变量转换为一列
【发布时间】:2022-01-22 22:57:21
【问题描述】:

我有类似这样的年龄列是虚拟编码的。 如何使用 dplyr 将这些列转换为一列?

输入:

  age_0-10 age_11-20 age_21-30 age_31-40 age_41-50 age_51-60 gender
1 0        1         0         0         0         0         0
2 0        0         1         0         0         0         1
3 0        0         0         1         0         0         0
4 0        1         0         0         0         0         1
5 0        0         0         0         0         1         1

预期输出:

age         gender
1 11-20     0
2 21-30     1
3 31-40     0
4 11-20     1
5 51-60     1

【问题讨论】:

标签: r dplyr


【解决方案1】:

这是另一个tidyverse 解决方案:

library(dplyr)
library(purrr)

df %>%
  mutate(age = pmap_chr(select(cur_data(), !gender), 
                        ~ names(df)[-ncol(df)][as.logical(c(...))])) %>%
  select(age, gender)

        age gender
1 age_11-20      0
2 age_21-30      1
3 age_31-40      0
4 age_11-20      1
5 age_51-60      1

【讨论】:

    【解决方案2】:

    使用max.col尝试下面的基本 R 代码

    cbind(
      age = gsub("^age_", "", head(names(df), -1)[max.col(df[-ncol(df)])]),
      df[ncol(df)]
    )
    

    给了

        age gender
    1 11-20      0
    2 21-30      1
    3 31-40      0
    4 11-20      1
    5 51-60      1
    

    【讨论】:

      【解决方案3】:

      一个可能的解决方案,现在,感谢@Adam 的评论,names_prefix

      library(tidyverse)
      
      df <- data.frame(
        check.names = FALSE,
        `age_0-10` = c(0L, 0L, 0L, 0L, 0L),
        `age_11-20` = c(1L, 0L, 0L, 1L, 0L),
        `age_21-30` = c(0L, 1L, 0L, 0L, 0L),
        `age_31-40` = c(0L, 0L, 1L, 0L, 0L),
        `age_41-50` = c(0L, 0L, 0L, 0L, 0L),
        `age_51-60` = c(0L, 0L, 0L, 0L, 1L),
        gender = c(0L, 1L, 0L, 1L, 1L)
      )
      
      df %>% 
        pivot_longer(col=starts_with("age"), names_to="age", names_prefix="age_") %>% 
        filter(value==1) %>%
        select(age, gender, -value)
      
      #> # A tibble: 5 × 2
      #>   age   gender
      #>   <chr>  <int>
      #> 1 11-20      0
      #> 2 21-30      1
      #> 3 31-40      0
      #> 4 11-20      1
      #> 5 51-60      1
      

      【讨论】:

      • 如果您在pivot_longer() 语句中使用names_prefix = "age_",您可以删除最后的mutate() 行。
      • 谢谢@Adam,让我知道! names_prefix 已经浮现在我的脑海中。我已经相应地编辑了我的答案。好点,亚当!
      • 没问题!这些功能中有很多小选项,很难跟踪。我只是碰巧最近做了很多旋转,所以这一切都在我脑海中浮现。
      • 这太棒了!如果年龄列有后缀,比如age_0-10_colage_11-20_col 等。我怎样才能去掉后缀?
      • 感谢@Peter Mortensen 的评论。老实说,我不认为真的需要这样的解释。但是,如果您认为确实需要,欢迎您自行插入该解释。
      【解决方案4】:

      这是在dplyr 中使用c_across() 的一种方式。

      library(dplyr)
      library(stringr)
      
      df %>% 
        rowwise() %>% 
        mutate(age = str_remove(names(.)[which(c_across(starts_with("age")) == 1)], "^age_")) %>% 
        ungroup() %>% 
        select(age, gender)
      
      # # A tibble: 5 x 2
      #   age   gender
      #   <chr>  <int>
      # 1 11-20      0
      # 2 21-30      1
      # 3 31-40      0
      # 4 11-20      1
      # 5 51-60      1
      

      【讨论】:

        猜你喜欢
        • 2020-11-21
        • 1970-01-01
        • 2018-01-26
        • 2023-03-13
        • 2019-09-27
        • 1970-01-01
        • 2018-10-31
        • 2017-07-27
        • 2021-08-19
        相关资源
        最近更新 更多