Этот вопрос связан с Как заменить факторные уровни n верхними уровнями (по некоторой метрике) плюс [другой]?. В качестве метрики я хочу использовать количество вхождений фактора. Я знаю, что могу сделать это, составив список случаев, но мне было интересно, есть ли способ получше.

Примере:

library(data.table);
library(plyr);
fac <- data.table(score = as.factor(c(3,4,5,3,3,3,5)));
ocCnt <- data.table(lapply(fac,count)$score);
fac$occurrence <- 0;
for(i in 1:length(fac$score)){fac$occurrence[i]<-ocCnt[x==fac$score[i]]$freq};

Затем я мог бы использовать функцию, описанную в указанном вопросе / ответе:

hotfactor= function(fac,by,n=10,o="other") {
   levels(fac)[rank(-xtabs(by~fac))[levels(fac)]>n] <- o
   fac
}

Чтобы продолжить пример, если мы хотим увидеть только самый популярный фактор, мы делаем:

hotfactor(fac$score,fac$occurrence,1);

Чтобы получить ответ:

[1] 3 других 3 3 3 других

Уровни: 3 другие

Итак, мой вопрос: могу ли я сделать это, не добавляя список, в котором учитываются вхождения?

Обратите внимание, что я хочу сделать это для n самых популярных факторов (а не только для самого популярного фактора).

r
0
Nieke Aerts 28 Окт 2015 в 13:15

2 ответа

Лучший ответ

Используйте table и which.max:

score <- factor(c(3,4,5,3,3,3,5))
levels(score)[- which.max(table(score))] <- "other"
#[1] 3     other other 3     3     3     other
#Levels: 3 other

Очевидно, это разрывает ничью, беря первое максимальное значение.

Если вы хотите сохранить два верхних уровня:

score <- factor(c(3, 4,5,3,3,3,5), levels =c(4,3,5))

levels(score)[!levels(score) %in% names(sort(table(score), decreasing = TRUE)[1:2])] <- "other"
#[1] 3     other 5     3     3     3     5    
#Levels: other 3 5
1
Roland 28 Окт 2015 в 10:33

Если вы не знаете, сколько уровней вам нужно сгруппировать, скажем, 90% ваших данных и готовы использовать dplyr, вы можете сделать что-то вроде следующих:

library(dplyr)

df <- data.frame(
        f = factor(mapply(rep, letters[1:5], 2^(1:5)) %>% unlist(use.names = F))
)

df %>% 
    count(f, sort = T) %>% 
    mutate(p = cumsum(n) / nrow(df))

#      A tibble: 5 x 3
#        f     n         p
#   <fctr> <int>     <dbl>
# 1      e    32 0.5161290
# 2      d    16 0.7741935
# 3      c     8 0.9032258
# 4      b     4 0.9677419
# 5      a     2 1.0000000

(top <- df %>% 
    count(f, sort = T) %>% 
    mutate(p = cumsum(n) / nrow(df)) %>%
    filter(cumall(p < .91)) %>% 
    select(f) %>% 
    unlist(use.names = F))

# [1] e d c
# Levels: a b c d e

levels(df$f) <- factor(c(levels(df$f), 'z'))
df$f[!df$f %in% top] <- 'z'

df %>% 
    count(f, sort = T) %>% 
    mutate(p = cumsum(n) / nrow(df))

#  A tibble: 4 x 3
#        f     n         p
#   <fctr> <int>     <dbl>
# 1      e    32 0.5161290
# 2      d    16 0.7741935
# 3      c     8 0.9032258
# 4      z     6 1.0000000
0
sbaldrich 28 Июл 2016 в 23:13