12

我很少使用因子,通常认为它们是可以理解的,但我经常对特定操作的细节感到模糊。目前,我正在将几乎没有观察到的类别编码/折叠到“其他”中,并且正在寻找一种快速的方法来做到这一点——我可能有 20 个级别的变量,但我有兴趣将它们中的一堆折叠成一个。

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()调用,将它们全部枚举,每当一个类别几乎没有观察到时,将它们归类为“其他”。

假设上述top8和以上是实际的前 8 名,那么声明为因子变量top8_desc的最佳方式是什么,以便正确编码中的值并将其他所有内容重新编码为?data$naicstop8other

4

4 回答 4

6

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

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

然后你可以在把它变成一个因素的时候使用“排除”选项

factor(data$naics, exclude=-99)
于 2013-03-20T20:23:43.980 回答
6

您可以使用forcats::fct_other()

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

fct_other()用作 a 的一部分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未设置参数,则其他级别默认为“Other”(大写“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'))
于 2018-04-06T21:15:13.953 回答
3

迟到的入场

这是一个plyr::mapvalues允许 aremaining参数(您的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)
于 2013-08-21T01:40:44.050 回答
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)
}
于 2013-08-20T13:51:31.883 回答