Como criar um índice consecutivo com base em uma variável de agrupamento em um dataframe

Eu tenho um quadro de dados ( all_data ) em que tenho uma lista de sites (1 … all_data ) e suas pontuações, por exemplo

  site score 1 10 1 11 1 12 4 10 4 11 4 11 8 9 8 8 8 7 

O que eu quero fazer é criar outra coluna no quadro de dados que all_data cada site em ordem numérica, por exemplo, no exemplo acima, de 1 a 3. Assim, all_data se pareceria com:

 site score number 1 10 1 1 11 1 1 12 1 4 10 2 4 11 2 4 11 2 8 9 3 8 8 3 8 7 3 

Tenho certeza que isso deve ser facilmente resolvido, mas ainda não encontrei um caminho.

Tente Data$number <- as.numeric(as.factor(Data$site))

Em um sidenote: a diferença entre a solução de mim e @Chase de um lado, e a de @DWin do outro, é a ordenação dos números. Ambos as.factor e factor as.factor automaticamente os níveis, enquanto isso não acontece na solução de @DWin:

 Dat <- data.frame(site = rep(c(1,8,4), each = 3), score = runif(9)) Dat$number <- as.numeric(factor(Dat$site)) Dat$sitenum <- match(Dat$site, unique(Dat$site) ) 

 > Dat site score number sitenum 1 1 0.7377561 1 1 2 1 0.3131139 1 1 3 1 0.7862290 1 1 4 8 0.4480387 3 2 5 8 0.3873210 3 2 6 8 0.8778102 3 2 7 4 0.6916340 2 3 8 4 0.3033787 2 3 9 4 0.6552808 2 3 

Duas outras opções:

1) Usando a function data.table pacote data.table :

 library(data.table) setDT(dat)[, num := .GRP, by = site] 

com o dataset de exemplo abaixo disso resulta em:

 > dat site score num 1: 1 0.14945795 1 2: 1 0.60035697 1 3: 1 0.94643075 1 4: 8 0.68835336 2 5: 8 0.50553372 2 6: 8 0.37293624 2 7: 4 0.33580504 3 8: 4 0.04825135 3 9: 4 0.61894754 3 10: 8 0.96144729 2 11: 8 0.65496051 2 12: 8 0.51029199 2 

2) Usando a function dplyr do dplyr :

 dat$num <- group_indices(dat, site) 

ou quando você quer trabalhar com avaliações fora do padrão:

 library(dplyr) dat %>% mutate(num = group_indices_(dat, .dots = c('site'))) 

o que resulta em:

  site score num 1 1 0.42480366 1 2 1 0.98736177 1 3 1 0.35766187 1 4 8 0.06243182 3 5 8 0.55617002 3 6 8 0.20304632 3 7 4 0.90855921 2 8 4 0.25215078 2 9 4 0.44981251 2 10 8 0.60288270 3 11 8 0.46946587 3 12 8 0.44941782 3 

Como pode ser visto, dplyr fornece uma ordem diferente dos números do grupo.


Se você quiser outro número toda vez que o grupo mudar, existem várias outras opções:

1) com base R:

 # option 1: dat$num <- cumsum(c(TRUE, head(dat$site, -1) != tail(dat$site, -1))) # option 2: x <- rle(dat$site)$lengths dat$num <- rep(seq_along(x), times=x) 

2) com o pacote data.table :

 library(data.table) setDT(dat)[, num := rleid(site)] 

que todos resultam em:

 > dat site score num 1 1 0.80817855 1 2 1 0.07881334 1 3 1 0.60092828 1 4 8 0.71477988 2 5 8 0.51384565 2 6 8 0.72011650 2 7 4 0.74994627 3 8 4 0.09564052 3 9 4 0.39782587 3 10 8 0.29446540 4 11 8 0.61725367 4 12 8 0.97427413 4 

Dados usados:

 dat <- data.frame(site = rep(c(1,8,4,8), each = 3), score = runif(12)) 

Isso deve ser bastante eficiente e compreensível:

 Dat$sitenum <- match(Dat$site, unique(Dat$site)) 

Você pode transformar o site em um fator e, em seguida, retornar os valores numéricos ou inteiros desse fator:

 dat <- data.frame(site = rep(c(1,4,8), each = 3), score = runif(9)) dat$number <- as.integer(factor(dat$site)) dat site score number 1 1 0.5305773 1 2 1 0.9367732 1 3 1 0.1831554 1 4 4 0.4068128 2 5 4 0.3438962 2 6 4 0.8123883 2 7 8 0.9122846 3 8 8 0.2949260 3 9 8 0.6771526 3 

Outra solução usando data.table :: frank ().

Exemplo com o datset mais completo fornecido por Jaap:

 setDT(dat)[, number := frank(site, ties.method = "dense")] dat site score number 1: 1 0.3107920 1 2: 1 0.3640102 1 3: 1 0.1715318 1 4: 8 0.7247535 3 5: 8 0.1263025 3 6: 8 0.4657868 3 7: 4 0.6915818 2 8: 4 0.3558270 2 9: 4 0.3376173 2 10: 8 0.7934963 3 11: 8 0.9641918 3 12: 8 0.9832120 3 

Nota : Isso também funciona se o site for um caractere ou fator.