【问题标题】:Rename categorical levels to reduce the number of levels重命名分类级别以减少级别数
【发布时间】:2019-12-22 12:39:42
【问题描述】:

我有一个分类列,在大约 78000 条记录的数据集中有大约 1200 个级别。我想根据事件降低水平。例如。 -:

  • 出现超过 2000 次的所有关卡都重命名为“A”。
  • 所有级别出现超过 1000 次但少于 2000 次 重命名为“B”
  • 所有级别出现超过 900 次但少于 1000 次 重命名为“C”

等等。

我不想将不太频繁出现的关卡分组到“其他”中,因为它会隐藏很多重要的关卡。
以下是以数据框为例。

df=data.frame(
  ID = c(1:10),
  Name = c("Jack", "Mike","Jack", "Mike","Jack", "Mike", "Tom", "Tom", "Smith", "Tony")
)

在这里,我想通过以下方式降低“名称”列的级别:

  • 将所有发生 >=3 次的关卡重命名为“A”
  • 重命名所有级别 >=2 但
  • 将所有发生的级别重命名为“C”

谁能帮我在 R 中做这件事?

【问题讨论】:

    标签: r


    【解决方案1】:

    我们可以使用add_count来统计Name的实例,然后用case_when检查条件

    library(dplyr)
    
    df %>% 
      add_count(Name) %>%
      mutate(NewName = case_when(n >= 3 ~'A', 
                                 n >= 2 & n < 3 ~'B', 
                                 TRUE ~'C')) %>%
      select(-n, -Name)
    
    #     ID NewName
    #   <int> <chr>  
    # 1     1 A      
    # 2     2 A      
    # 3     3 A      
    # 4     4 A      
    # 5     5 A      
    # 6     6 A      
    # 7     7 B      
    # 8     8 B      
    # 9     9 C      
    #10    10 C      
    

    【讨论】:

      【解决方案2】:

      使用table 的基本 R 解决方案

      NameCount = table(df$Name)[df$Name]
      NewName = rep("C", length(NameCount))
      NewName[NameCount >= 2] = "B"
      NewName[NameCount >= 3] = "A"
      NewName
       [1] "A" "A" "A" "A" "A" "A" "B" "B" "C" "C"
      

      【讨论】:

        【解决方案3】:

        我们可以使用data.table (1.12.9) 的开发版本中的fcase,它也可以懒惰地进行评估

        library(data.table)
        setDT(df)[, NewName := fcase(.N >=3, 'A',
                                     .N >=2 & .N < 3, 'B',
                                     default = 'C'), Name][]
        #    ID  Name NewName
        # 1:  1  Jack       A
        # 2:  2  Mike       A
        # 3:  3  Jack       A
        # 4:  4  Mike       A
        # 5:  5  Jack       A
        # 6:  6  Mike       A
        # 7:  7   Tom       B
        # 8:  8   Tom       B
        # 9:  9 Smith       C
        #10: 10  Tony       C
        

        或者使用base RfindInterval

        with(df, rev(LETTERS[1:3])[findInterval(table(Name)[Name], 2:3) + 1])
        #[1] "A" "A" "A" "A" "A" "A" "B" "B" "C" "C"
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多