Pergunta

Tenho um tbl_df onde quero group_by(u, v) para cada combinação inteira distinta observada com (u, v).


EDITAR: isso foi resolvido adicionando group_indices() de volta dplyr 0.4.0


a) Quero então atribuir a cada grupo distinto algum rótulo numérico distinto arbitrário = 1,2,3...por exemplo.a combinação (u,v)==(2,3) poderia obter o rótulo 1, (1,3) poderia obter 2 e assim por diante.Como fazer isso com um mutate(), sem um resumo e auto-junção em três etapas?

dplyr tem uma função bacana n(), mas isso dá o número de elementos dentro de seu grupo, não o geral número do grupo. Em data.table isso seria simplesmente chamado .GRP.

b) Na verdade, o que eu realmente quero atribuir um rótulo de string/caractere ('A','B',...).Mas numerar grupos por números inteiros é bom o suficiente, porque posso então usar integer_to_label(i) como abaixo.A menos que haja uma maneira inteligente de mesclar esses dois?Mas não se preocupe com 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 <- tbl_df(data.frame(u=sample.int(3,10,replace=T), v=sample.int(4,10,replace=T)))

# Want to label/number each distinct group of unique (u,v) combinations
df %>% group_by(u,v) %>% mutate(label = n()) # WRONG: n() is number of element within its group, not overall number of group

   u v
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
Foi útil?

Solução

Resposta atualizada

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())

Você também pode considerar a seguinte versão ligeiramente ilegível

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

usando iterators pacote

library(iterators)

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

Outras dicas

dplyr tem um group_indices() função que você pode usar assim:

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

Outra abordagem usando data.table seria

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

o que resulta em:

    u v 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

Atualizando minha resposta de três maneiras diferentes:

A) Uma solução simples e não dplyr usando 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) Tornando a resposta da função geradora rápida e suja de Randy mais 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) Também aqui está um one-liner usando uma função geradora abusando de uma atribuição de variável global de esse:

i <- 0
generate_integer <- function() { return(assign('i', i+1, envir = .GlobalEnv)) }

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

rm(i)

Não tenho reputação suficiente para um comentário, então estou postando uma resposta.

A solução usando factor() é boa, mas tem a desvantagem de que os números dos grupos são atribuídos depois que factor() coloca seus níveis em ordem alfabética.O mesmo comportamento acontece com group_indices() do dplyr.Talvez você queira que os números dos grupos sejam atribuídos de 1 a n com base na ordem atual dos grupos.Nesse caso, você pode usar:

my_tibble %>% mutate(group_num = as.integer(factor(group_var, levels = unique(.$group_var))) )
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top