【问题标题】:Reorder factor levels by pattern按模式重新排序因子水平
【发布时间】:2021-04-09 00:16:38
【问题描述】:

我有一个因素可以识别调查数据集中的分层。我想重新排序因子,使某些字符模式排在其他字符模式之前。

例如,我有一个表示性别、年龄和教育程度的混合因素:

my_factor <- factor(levels=c(1:8),
                    labels=c("Male-18_34-HS","Female-35_49-HS",
                             "Male-18_34-CG", "Female-18_34-CG",
                             "Male-35_49-HS", "Male-35_49-CG",
                             "Female-18_34-HS", "Female-35_49-CG"),
                    ordered=TRUE)

我希望先按所有女性类别排序,然后按正确顺序按年龄类别排序,然后按正确顺序按教育类别排序。我可以通过forcats::fct_relevel 到达那里的大部分地方:

forcats::fct_relevel(my_factor, sort)

ordered(0)
8 Levels: Female-18_34-CG < Female-18_34-HS < Female-35_49-CG < Female-35_49-HS < Male-18_34-CG < Male-18_34-HS < ... < Male-35_49-HS

但教育类别的顺序错误。有没有办法确保“HS”在“CG”之前,但保持性别和年龄组的顺序相同?

【问题讨论】:

    标签: r forcats


    【解决方案1】:

    您可以制作参考表,按列因子级别排列:

    library(dplyr)
    library(tidyr)
    
    ref <- tibble(key = c("Male-18_34-HS","Female-35_49-HS",
                          "Male-18_34-CG", "Female-18_34-CG",
                          "Male-35_49-HS", "Male-35_49-CG",
                          "Female-18_34-HS", "Female-35_49-CG"))
    
    ref <- separate(ref, key, into = c("gender", "age", "education"), sep = "-", remove = FALSE) %>%
      mutate(across("gender", factor, c("Female", "Male")),
             across("age", factor, c("18_34", "35_49")),
             across("education", factor, c("HS", "CG"))) %>%
      arrange(gender, age, education)
    

    然后申请:

    factor(d, levels = ref$key)

    【讨论】:

      【解决方案2】:

      您可以通过编程方式创建所需的因子水平。

      lvls <- do.call(paste, c(tidyr::expand_grid(
                 c('Female', 'Male'), c('18_34', '35_49'), c('HS', 'CG')), sep = '-'))
      lvls
      #[1] "Female-18_34-HS" "Female-18_34-CG" "Female-35_49-HS" "Female-35_49-CG"
      #[5] "Male-18_34-HS"   "Male-18_34-CG"   "Male-35_49-HS"   "Male-35_49-CG"
      

      您可以将此lvls 用作factor 调用中的级别。

      【讨论】:

        【解决方案3】:

        您可以使用str_split 来拆分标签,对生成的列表进行排序,并相应地重建级别:

        lvl <- do.call(rbind,stringr::str_split(levels(my_factor),'-'))
        lvl <- apply(lvl[order(lvl[,1],lvl[,2],lvl[,3]),],1,paste0,collapse='-')
        my_factor <- factor(my_factor,levels = lvl)
        
        levels(my_factor)
        #> [1] "Female-18_34-CG" "Female-18_34-HS" "Female-35_49-CG" "Female-35_49-HS"
        #> [5] "Male-18_34-CG"   "Male-18_34-HS"   "Male-35_49-CG"   "Male-35_49-HS"
        

        【讨论】:

          【解决方案4】:
          dft<-c("Male-18_34-HS","Female-35_49-HS", "Male-18_34-CG", "Female-18_34-CG", "Male-35_49-HS", "Male-35_49-CG", "Female-18_34-HS", "Female-35_49-CG")
          
          gender<-unlist(lapply(dft, FUN=function(x) str_split(x,'-')[[1]][1]))
          age<-unlist(lapply(dft, FUN=function(x) str_split(x,'-')[[1]][1]))
          ed<-unlist(lapply(dft, FUN=function(x) str_split(x,'-')[[1]][3]))
          
          order_f<-order(gender,age,sort(ed,decreasing = T))
          
          my_factor <- factor(levels=c(1:8),
                              labels=dft[order_f],
                              ordered=TRUE)
          

          【讨论】:

            猜你喜欢
            • 2019-04-12
            • 1970-01-01
            • 2020-09-29
            • 1970-01-01
            • 1970-01-01
            • 2017-12-22
            • 2022-01-10
            • 1970-01-01
            相关资源
            最近更新 更多