Quadro de dados do subconjunto com base no número de linhas por grupo

Eu tenho dados como este, onde alguns “nomes” ocorrem mais de 3 vezes:

df <- data.frame(name = c("a", "a", "a", "b", "b", "c", "c", "c", "c"), x = 1:9) 

Desejo subconjugar (filtrar) os dados com base no número de linhas (observações) dentro de cada nível da variável “name”. Se um determinado nível de “nome” ocorrer mais do que 3 vezes, desejo remover todas as linhas pertencentes a esse nível.

Eu escrevi este código, mas não consigo fazê-lo funcionar.

 as.data.frame(table(unique(df)$name)) subset(df, name > 3) 

   

    Primeiro, duas alternativas de base . Um depende da table e o outro da ave e do length . Então, duas maneiras de dados.


    1. table

     tt < - table(df$name) df2 <- subset(df, name %in% names(tt[tt < 3])) # or df2 <- df[df$name %in% names(tt[tt < 3]), ] 

    Se você quiser percorrê-lo passo a passo:

     # count each 'name', assign result to an object 'tt' tt < - table(df$name) # which 'name' in 'tt' occur more than three times? # Result is a logical vector that can be used to subset the table 'tt' tt < 3 # from the table, select 'name' that occur < 3 times tt[tt < 3] # ...their names names(tt[tt < 3]) # rows of 'name' in the data frame that matches "the < 3 names" # the result is a logical vector that can be used to subset the data frame 'df' df$name %in% names(tt[tt < 3]) # subset data frame by a logical vector # 'TRUE' rows are kept, 'FALSE' rows are removed. # assign the result to a data frame with a new name df2 <- subset(df, name %in% names(tt[tt < 3])) # or df2 <- df[df$name %in% names(tt[tt < 3]), ] 

    2. ave e length

    Como sugerido por @flodel:

     df[ave(df$x, df$name, FUN = length) < 3, ] 

    3. data.table : .N e .SD :

     library(data.table) setDT(df)[, if (.N < 3) .SD, by = name] 

    4. data.table : .N e .I :

     setDT(df) df[df[, .I[.N < 3], name]$V1] 

    Veja também o Q & A relacionado Contagem de número de observações / linhas por grupo e adicione resultado ao quadro de dados .

    Usando o pacote dplyr :

     df %>% group_by(name) %>% filter(n() < 4)