Vraag R: factor niveaus, recode rest naar 'overig'


Ik gebruik factoren enigszins onregelmatig en vind ze over het algemeen begrijpelijk, maar ik ben vaak wazig over de details voor specifieke bewerkingen. Momenteel ben ik bezig met het coderen / samenvouwen van categorieën met weinig observaties in "andere" en ben op zoek naar een snelle manier om dat te doen - ik heb misschien 20 niveaus van een variabele, maar ben geïnteresseerd in het samenvouwen van een aantal daarvan.

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)

)

Hier zijn mijn interessegraden en hun labels in afzonderlijke vectoren.

#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')

Ik zou de kunnen gebruiken factor() bel, toon ze allemaal op, classificerend als "ander" voor elke keer dat een categorie weinig waarnemingen had.

Ervan uitgaande dat de 'top8' en 'top8_desc' hierboven de feitelijke top 8 zijn, wat is de beste manier om data $ naics als een factorvariabele te declareren en al het andere te hercoderen als 'ander'?


10
2018-03-20 20:05


oorsprong


antwoorden:


Ik denk dat de eenvoudigste manier is om alle nautica niet in de top 8 te herlabelen naar een speciale waarde.

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

Vervolgens kunt u de optie "uitsluiten" gebruiken wanneer u er een factor van maakt

factor(data$naics, exclude=-99)

6
2018-03-20 20:23



Een late invoer

Hier is een wrapper voor plyr::mapvalues waardoor de a remaining argument (jouw 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
2017-08-21 01:40



Je kunt gebruiken forcats::fct_other():

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

Of gebruik fct_other() als een onderdeel van een 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

Merk op dat als het argument other_level is niet ingesteld, de andere niveaus staan ​​standaard op 'Overig' (hoofdletter 'O').

En omgekeerd, als je slechts een paar factoren had die je naar 'ander' wilde omzetten, zou je het argument kunnen gebruiken drop in plaats daarvan:

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 heeft ook recode_factor() waar je de kunt instellen .default argument voor andere, maar met een groter aantal niveaus om te hercoderen, zoals bij dit voorbeeld, zou het vervelend kunnen zijn:

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'))

3
2018-04-06 21:15



Ik heb een functie geschreven om dit te doen dat nuttig kan zijn voor anderen? Ik controleer eerst op een relatieve manier of een niveau minder voorkomt dan mp procent van de basis. Daarna controleer ik om het maximum aantal niveaus te beperken tot ml.

ds is de dataset bij de hand van het type data.frame, ik doe dit voor alle kolommen die in cat_var_names als factoren verschijnen.

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)
}

0
2017-08-20 13:51