R:因子水平,重新编码为'其他'

时间:2013-03-20 20:05:12

标签: r r-factor

我使用的因素很少,并且通常发现它们易于理解,但我经常对特定操作的细节模糊不清。目前,我正在编写/折叠类别,很少有观察到“其他”,我正在寻找一个快速的方法来做到这一点 - 我有一个或许20级的变量,但我有兴趣将它们中的一堆折叠成一个。 / p>

data <- data.frame(employees = sample.int(1000,500),
                   naics = sample(c('621111','621112','621210','621310','621320','621330','621340','621391','621399','621410','621420','621491','621492','621493','621498','621511','621512','621610','621910','621991','621999'),
                                  100, replace=T))

以下是我感兴趣的级别,以及它们在不同向量中的标签。

#levels and labels
top8 <-c('621111','621210','621399','621610','621330',
         '621310','621511','621420','621320')
top8_desc <- c('Offices of physicians',
               'Offices of dentists',
               'Offices of all other miscellaneous health practitioners',
               'Home health care services',
               'Offices of Mental Health Practitioners',
               'Offices of chiropractors',
               'Medical Laboratories',
               'Outpatient Mental Health and Substance Abuse Centers',
               'Offices of optometrists')

我可以使用factor()调用,将它们全部枚举,每次类别几乎没有观察时将其归类为“其他”。

假设上面的top8top8_desc是实际的前8位,那么将data$naics声明为因子变量的最佳方式是什么,以便top8中的值是否进行了正确编码,其他所有内容都被重新编码为other

4 个答案:

答案 0 :(得分:6)

我认为最简单的方法是将不在前8位的所有naics重新标记为特殊值。

data$naics[!(data$naics %in% top8)] = -99

然后,您可以在将其转换为因子

时使用“排除”选项
factor(data$naics, exclude=-99)

答案 1 :(得分:4)

您可以使用forcats::fct_other()

library(forcats)
data$naics <- fct_other(data$naics, keep = top8, other_level = 'other')

或使用fct_other()作为dplyr::mutate()的一部分:

library(dplyr)
data <- mutate(data, naics = fct_other(naics, keep = top8, other_level = 'other')) 

data %>% head(10)
   employees  naics
1        420  other
2        264  other
3        189  other
4        157 621610
5        376 621610
6        236  other
7        658 621320
8        959 621320
9        216  other
10       156  other

请注意,如果未设置参数other_level,则其他级别默认为“其他”(大写“O”)。

相反,如果您只想将几个因素转换为“其他”,则可以改为使用参数drop

data %>%  
  mutate(keep_fct = fct_other(naics, keep = top8, other_level = 'other'),
         drop_fct = fct_other(naics, drop = top8, other_level = 'other')) %>% 
  head(10)

   employees  naics keep_fct drop_fct
1        474 621491    other   621491
2        805 621111   621111    other
3        434 621910    other   621910
4        845 621111   621111    other
5        243 621340    other   621340
6        466 621493    other   621493
7        369 621111   621111    other
8         57 621493    other   621493
9        144 621491    other   621491
10       786 621910    other   621910

dpylr也有recode_factor(),您可以将.default参数设置为其他参数,但要重新编码的级别数较多,就像这个示例一样,可能很乏味:

data %>% 
   mutate(naices = recode_factor(naics, `621111` = '621111', `621210` = '621210', `621399` = '621399', `621610` = '621610', `621330` = '621330', `621310` = '621310', `621511` = '621511', `621420` = '621420', `621320` = '621320', .default = 'other'))

答案 2 :(得分:3)

迟到的条目

以下是plyr::mapvalues的包装器,它允许remaining参数(您的other

library(plyr)

Mapvalues <- function(x, from, to, warn_missing= TRUE, remaining = NULL){
  if(!is.null(remaining)){
    therest <- setdiff(x, from)
    from <- c(from, therest)
    to <- c(to, rep_len(remaining, length(therest)))
  }
  mapvalues(x, from, to, warn_missing)
}
# replace the remaining values with "other"
Mapvalues(data$naics, top8, top8_desc,remaining = 'other')
# leave the remaining values alone
Mapvalues(data$naics, top8, top8_desc)

答案 3 :(得分:0)

我已经写了一个功能,可以对其他人有用吗? 我首先以相对的方式检查,如果一个水平发生的数量低于基数的mp%。之后,我检查将最大级别数限制为ml。

ds是data.frame类型的数据集,我对cat_var_names中出现的所有列执行此操作。

cat_var_names <- names(clean_base[sapply(clean_base, is.factor)])

recodeLevels <- function (ds = clean_base, var_list = cat_var_names, mp = 0.01, ml = 25) {
  # remove less frequent levels in factor
  # 
  n <- nrow(ds)
  # keep levels with more then mp percent of cases
  for (i in var_list){
    keep <- levels(ds[[i]])[table(ds[[i]]) > mp * n]
    levels(ds[[i]])[which(!levels(ds[[i]])%in%keep)] <- "other"
  }

  # keep top ml levels
  for (i in var_list){
    keep <- names(sort(table(ds[i]),decreasing=TRUE)[1:ml])
    levels(ds[[i]])[which(!levels(ds[[i]])%in%keep)] <- "other"
  }
  return(ds)
}