Trabalhando com um quadro de dados semelhante a este:
set.seed(100)
df <- data.frame(cat = c(rep("aaa", 5), rep("bbb", 5), rep("ccc", 5)), val = runif(15))
df <- df[order(df$cat, df$val), ]
df
cat val
1 aaa 0.05638315
2 aaa 0.25767250
3 aaa 0.30776611
4 aaa 0.46854928
5 aaa 0.55232243
6 bbb 0.17026205
7 bbb 0.37032054
8 bbb 0.48377074
9 bbb 0.54655860
10 bbb 0.81240262
11 ccc 0.28035384
12 ccc 0.39848790
13 ccc 0.62499648
14 ccc 0.76255108
15 ccc 0.88216552
Estou tentando adicionar uma coluna com numeração dentro de cada grupo. Fazer dessa maneira obviamente não está usando os poderes do R:
df$num <- 1
for (i in 2:(length(df[,1]))) {
if (df[i,"cat"]==df[(i-1),"cat"]) {
df[i,"num"]<-df[i-1,"num"]+1
}
}
df
cat val num
1 aaa 0.05638315 1
2 aaa 0.25767250 2
3 aaa 0.30776611 3
4 aaa 0.46854928 4
5 aaa 0.55232243 5
6 bbb 0.17026205 1
7 bbb 0.37032054 2
8 bbb 0.48377074 3
9 bbb 0.54655860 4
10 bbb 0.81240262 5
11 ccc 0.28035384 1
12 ccc 0.39848790 2
13 ccc 0.62499648 3
14 ccc 0.76255108 4
15 ccc 0.88216552 5
Qual seria uma boa maneira de fazer isso?
Respostas:
Use
ave
,ddply
,dplyr
oudata.table
:ou:
ou:
ou (o mais eficiente em memória, conforme designado por referência dentro
DT
):fonte
ave
fornece um float em vez de um int aqui. Como alternativa, pode mudardf$val
paraseq_len(nrow(df))
. Eu apenas corri para este aqui: stackoverflow.com/questions/42796857/...data.table
solução parece ser mais rápido do que usarfrank
:library(microbenchmark); microbenchmark(a = DT[, .(val ,num = frank(val)), by = list(cat)] ,b =DT[, .(val , id = seq_len(.N)), by = list(cat)] , times = 1000L)
dplyr
solução é boa. Mas se, como eu, você foi ficando erros estranhos ao tentar essa abordagem, certifique-se de que você não está recebendo os conflitos entreplyr
edplyr
como explicado neste post Ela pode ser evitada por explicitamente chamandodplyr::mutate(...)
data.table
método ésetDT(df)[, id:=rleid(val), by=.(cat)]
library(plyr)
elibrary(dplyr)
respostas para tornar a coluna val de classificação em ordem decrescente?Por fazer isso r-faqpergunta mais completa, uma alternativa R básica com
sequence
erle
:que fornece o resultado pretendido:
Se
df$cat
é uma variável de fator, você precisa envolvê-laas.character
primeiro:fonte
cat
coluna seja classificada?cat
Aqui está uma opção usando um
for
loop por grupos e não por linhas (como o OP fez)fonte
Aqui está um pequeno truque de melhoria que permite classificar 'val' dentro dos grupos:
fonte
Gostaria de adicionar uma
data.table
variante usando arank()
função que fornece a possibilidade adicional de alterar a ordem e, assim, a torna um pouco mais flexível que aseq_len()
solução e é bastante semelhante às funções row_number no RDBMS.fonte
Outra
dplyr
possibilidade poderia ser:fonte
1:n()
usar,seq_len(n())
é mais seguro, caso sua sequência de operações tenha uma situação em quen()
possa retornar0
, porque1:0
fornece um vetor de comprimento dois e, ao mesmo tempo,seq_len(0)
um vetor de comprimento zero, evitando assim um erro de incompatibilidade de comprimentomutate()
.Usando a
rowid()
função emdata.table
:fonte