2014-06-17 20 views
7

Voglio sottoporre a serie un dataframe per fattore. Voglio solo mantenere i livelli dei fattori al di sopra di una certa frequenza.Un modo elegante per eliminare livelli di fattori rari dal frame dati

df <- data.frame(factor = c(rep("a",5),rep("b",5),rep("c",2)), variable = rnorm(12)) 

Questo codice crea frame di dati:

factor variable 
1  a -1.55902013 
2  a 0.22355431 
3  a -1.52195456 
4  a -0.32842689 
5  a 0.85650212 
6  b 0.00962240 
7  b -0.06621508 
8  b -1.41347823 
9  b 0.08969098 
10  b 1.31565582 
11  c -1.26141417 
12  c -0.33364069 

E voglio far cadere i livelli di fattore che ripetono meno di 5 volte. Ho sviluppato un ciclo for e funziona:

for (i in 1:length(levels(df$factor))){ 
    if(table(df$factor)[i] < 5){ 
    df.new <- df[df$factor != names(table(df$factor))[i],] 
    } 
} 

Ma esistono soluzioni più rapide e più carine?

risposta

6

Che dire

df.new <- df[!(as.numeric(df$factor) %in% which(table(df$factor)<5)),] 
0

Prova questo con funzioni base ...

lvl = as.data.frame(table(df$factor)) 
colnames(lvl) = c('factor','count') 
lvl 
    factor count 
1  a  5 
2  b  5 
3  c  2 

df[df$factor %in% lvl[lvl$count>=5,]$factor,] 
    factor variable 
1  a -0.01619026 
2  a 0.94383621 
3  a 0.82122120 
4  a 0.59390132 
5  a 0.91897737 
6  b 0.78213630 
7  b 0.07456498 
8  b -1.98935170 
9  b 0.61982575 
10  b -0.05612874 
3

Forse si uniscono con un conteggio filtrato dei fattori:

library(dplyr) 
common.factors <- df %.% group_by(factor) %.% tally() %.% filter(n >= 5) 
df.1 <- semi_join(df, common.factors) 
+1

Probabilmente si desidera un semi join – hadley

5
library(data.table) 
setDT(df)[, variable[.N >= 5], by = factor] 

## factor   V1 
## 1:  a -0.8204684 
## 2:  a 0.4874291 
## 3:  a 0.7383247 
## 4:  a 0.5757814 
## 5:  a -0.3053884 
## 6:  b 1.5117812 
## 7:  b 0.3898432 
## 8:  b -0.6212406 
## 9:  b -2.2146999 
## 10:  b 1.1249309 
+2

+1 e Wow, 'data.table' continua a impressionare. La mia unica critica sarebbe che è difficile da leggere. – Hugh

+2

@Hugh, com'è più difficile di 'dplyr' :)? –

+2

@DavidArenburg controlla la soluzione 'dplyr' da @beginneR. trovo anche molto più facile leggere la grammatica 'dplyr' di' data.table'. – rrs

8
require(dplyr) 

df %>% group_by(factor) %>% filter(n() >= 5) 
#factor variable 
#1  a 2.0769363 
#2  a 0.6187513 
#3  a 0.2426108 
#4  a -0.4279296 
#5  a 0.2270024 
#6  b -0.6839748 
#7  b -0.3285610 
#8  b 0.2625743 
#9  b -0.9532957 
#10  b 1.4526317 
4

Fino a poco tempo avrei accettato con group_by + filtro. Tuttavia, con la nuova forcats pacchetto dal tidyverse un'altra soluzione sarebbe

require(forcats) 
require(dplyr) 

df %>% filter(fct_lump(factor, n=5) != "Other") 

potremmo anche fare un po 'più espressiva utilizzando NA per la categoria a bassa frequenza:

df %>% filter(!is.na(fct_lump(factor, n=5, other_level=NA))) 
Problemi correlati