Cómo agregar el recuento de valores únicos por grupo a R data.frame

Deseo contar el número de valores únicos agrupando una segunda variable y luego agregar el conteo al data.frame existente como una nueva columna. Por ejemplo, si el dataframe existente tiene este aspecto:

color type 1 black chair 2 black chair 3 black sofa 4 green sofa 5 green sofa 6 red sofa 7 red plate 8 blue sofa 9 blue plate 10 blue chair 

Quiero agregar para cada color , el recuento de types únicos que están presentes en los datos:

  color type unique_types 1 black chair 2 2 black chair 2 3 black sofa 2 4 green sofa 1 5 green sofa 1 6 red sofa 2 7 red plate 2 8 blue sofa 3 9 blue plate 3 10 blue chair 3 

Esperaba usar ave , pero parece que no puedo encontrar un método sencillo que no requiera muchas líneas. Tengo> 100,000 filas, así que tampoco estoy seguro de cuán importante es la eficiencia.

Es algo similar a este problema: cuente el número de observaciones / filas por grupo y agregue el resultado al dataframe

Usando ave (ya que lo pides específicamente):

 within(df, { count <- ave(type, color, FUN=function(x) length(unique(x)))}) 

Asegúrese de que el type sea ​​vector de caracteres y no factor.


Como también dice que sus datos son enormes y que la velocidad / el rendimiento pueden ser un factor, sugiero también una solución de datos.

 require(data.table) setDT(df)[, count := uniqueN(type), by = color] # v1.9.6+ # if you don't want df to be modified by reference ans = as.data.table(df)[, count := uniqueN(type), by = color] 

uniqueN se implementó en v1.9.6 y es un equivalente más rápido de length(unique(.)) . Además, también funciona con data.frames / data.tables.


Otras soluciones

Usando plyr:

 require(plyr) ddply(df, .(color), mutate, count = length(unique(type))) 

Usando aggregate :

 agg <- aggregate(data=df, type ~ color, function(x) length(unique(x))) merge(df, agg, by="color", all=TRUE) 

Aquí hay una solución con el paquete dplyr : tiene n_distinct() como un contenedor de length(unique()) .

 df %>% group_by(color) %>% mutate(unique_types = n_distinct(type)) 

Esto también se puede lograr en un vectorizado sin operaciones grupales combinando unique table unique o tabulate

Si df$color es factor , entonces

Ya sea

 table(unique(df)$color)[as.character(df$color)] # black black black green green red red blue blue blue # 2 2 2 1 1 2 2 3 3 3 

O

 tabulate(unique(df)$color)[as.integer(df$color)] # [1] 2 2 2 1 1 2 2 3 3 3 

Si df$color es un character , solo

 table(unique(df)$color)[df$color] 

Si df$color es un integer entonces solo

 tabulate(unique(df)$color)[df$color]