¿Cómo numerar / etiquetar la tabla de datos por número de grupo de group_by?

Tengo un tbl_df donde quiero group_by(u, v) para cada combinación entera distinta observada con (u, v) .


EDITAR: esto se resolvió añadiendo group_indices() en dplyr 0.4.0


a) Entonces quiero asignar a cada grupo distinto una etiqueta de número distinto arbitrario = 1,2,3 … por ejemplo, la combinación (u, v) == (2,3) podría obtener la etiqueta 1, (1,3) podría obtener 2, y así sucesivamente. ¿Cómo hacer esto con un mutate() , sin un resumen de tres pasos y autoinscripción?

dplyr tiene una función ordenada n() , pero eso da la cantidad de elementos dentro de su grupo, no el número total del grupo . En data.table esto simplemente se llamará .GRP .

b) En realidad, lo que realmente quiero asignar es una etiqueta de cadena / caracteres (‘A’, ‘B’, …). Pero numerar grupos por enteros es suficiente, porque puedo usar integer_to_label(i) como se muestra a continuación. A menos que haya una forma inteligente de fusionar estos dos? Pero no te preocupes por esta parte.

 set.seed(1234) # Helper fn for mapping integer 1..26 to character label integer_to_label <- function(i) { substr("ABCDEFGHIJKLMNOPQRSTUVWXYZ",i,i) } df % group_by(u,v) %>% mutate(label = n()) # WRONG: n() is number of element within its group, not overall number of group uv 1 2 3 2 1 3 3 1 2 4 2 3 5 1 2 6 3 3 7 1 3 8 1 2 9 3 1 10 3 4 KLUDGE 1: could do df %>% group_by(u,v) %>% summarize(label = n()) , then self-join 

Respuesta actualizada

 get_group_number = function(){ i = 0 function(){ i < <- i+1 i } } group_number = get_group_number() df %>% group_by(u,v) %>% mutate(label = group_number()) 

También puede considerar la siguiente versión poco legible

 group_number = (function(){i = 0; function() i < <- i+1 })() df %>% group_by(u,v) %>% mutate(label = group_number()) 

usando el paquete de iterators

 library(iterators) counter = icount() df %>% group_by(u,v) %>% mutate(label = nextElem(counter)) 

dplyr tiene una función group_indices() que puede usar así:

 df %>% mutate(label = group_indices(., u, v)) %>% group_by(label) ... 

Otro enfoque que usa data.table sería

 require(data.table) setDT(df)[,label:=.GRP, by = c("u", "v")] 

lo que resulta en:

  uv label 1: 2 1 1 2: 1 3 2 3: 2 1 1 4: 3 4 3 5: 3 1 4 6: 1 1 5 7: 3 2 6 8: 2 3 7 9: 3 2 6 10: 3 4 3 

Actualizando mi respuesta de tres maneras diferentes:

A) Una solución ordenada sin dplyr que usa la interaction(u,v) :

 > df$label < - factor(interaction(df$u,df$v, drop=T)) [1] 1.3 2.3 2.2 2.4 3.2 2.4 1.2 1.2 2.1 2.1 Levels: 2.1 1.2 2.2 3.2 1.3 2.3 2.4 > match(df$label, levels(df$label)[ rank(unique(df$label)) ] ) [1] 1 2 3 4 5 4 6 6 7 7 

B) Hacer que la respuesta limpia y sucia del generador de Randy sea más compacta:

 get_next_integer = function(){ i = 0 function(u,v){ i < <- i+1 } } get_integer = get_next_integer() df %>% group_by(u,v) %>% mutate(label = get_integer()) 

C) También aquí hay un trazador de líneas usando una función de generador que abusa de una asignación de variable global de esto :

 i < - 0 generate_integer <- function() { return(assign('i', i+1, envir = .GlobalEnv)) } df %>% group_by(u,v) %>% mutate(label = generate_integer()) rm(i) 

No tengo suficiente reputación para un comentario, así que estoy publicando una respuesta en su lugar.

La solución que usa factor () es buena, pero tiene la desventaja de que los números de grupo se asignan después de que factor () alfabetiza sus niveles. El mismo comportamiento ocurre con dndr’s group_indices (). Quizás desee que los números de grupo se asignen de 1 a n en función del orden de grupo actual. En ese caso, puede usar:

 my_tibble %>% mutate(group_num = as.integer(factor(group_var, levels = unique(.$group_var))) )