Je souhaite créer un numéro séquentiel dans chaque série de valeurs égales, comme un compteur d'occurrences, qui redémarre une fois que la valeur de la ligne en cours diffère de la ligne précédente.
Veuillez trouver un exemple d’entrée et de sortie attendue ci-dessous.
dataset <- data.frame(input = c("a","b","b","a","a","c","a","a","a","a","b","c"))
dataset$counter <- c(1,1,2,1,2,1,1,2,3,4,1,1)
dataset
# input counter
# 1 a 1
# 2 b 1
# 3 b 2
# 4 a 1
# 5 a 2
# 6 c 1
# 7 a 1
# 8 a 2
# 9 a 3
# 10 a 4
# 11 b 1
# 12 c 1
Ma question est très similaire à celle-ci: Séquence cumulative d'occurrences de valeurs .
Vous devez utiliser sequence
et rle
:
> sequence(rle(as.character(dataset$input))$lengths)
[1] 1 1 2 1 2 1 1 2 3 4 1 1
Une version efficace et plus simple de la fonction écrite ci-dessous est maintenant disponible dans le package data.table, appelée rleid
. En utilisant cela, c'est juste:
setDT(dataset)[, counter := seq_len(.N), by=rleid(input)]
Voir ?rleid
pour plus d'informations sur l'utilisation et les exemples. Merci à @Henrik pour la suggestion de mettre à jour ce post.
rle
est certainement le moyen le plus pratique de le faire (+1 @ Ananda's). Mais on pourrait faire mieux (en termes de vitesse) sur des données plus volumineuses. Vous pouvez utiliser les fonctions duplist
et vecseq
(non exportées) à partir de data.table
comme suit:
require(data.table)
arun <- function(y) {
w = data.table:::duplist(list(y))
w = c(diff(w), length(y)-tail(w,1L)+1L)
data.table:::vecseq(rep(1L, length(w)), w, length(y))
}
x <- c("a","b","b","a","a","c","a","a","a","a","b","c")
arun(x)
# [1] 1 1 2 1 2 1 1 2 3 4 1 1
Benchmarking sur Big Data:
set.seed(1)
x <- sample(letters, 1e6, TRUE)
# rle solution
ananda <- function(y) {
sequence(rle(y)$lengths)
}
require(microbenchmark)
microbenchmark(a1 <- arun(x), a2<-ananda(x), times=100)
Unit: milliseconds
expr min lq median uq max neval
a1 <- arun(x) 123.2827 132.6777 163.3844 185.439 563.5825 100
a2 <- ananda(x) 1382.1752 1899.2517 2066.4185 2247.233 3764.0040 100
identical(a1, a2) # [1] TRUE
Le paquet runner a une solution dédiée pour calculer ce qui est nécessaire. streak_run
est la solution la plus rapide et accepte le vecteur en tant qu'entrée.
library(microbenchmark); library(runner)
x <- sample(letters, 1e6, TRUE)
ananda <- function(y) sequence(rle(y)$lengths)
microbenchmark( a2<-ananda(x), runner <- streak_run(x), times=100)
#Unit: milliseconds
# expr min lq mean median uq max neval
# a2 <- ananda(x) 580.744 718.117 1059.676 944.073 1399.649 1699.293 10
#run <- streak_run(x) 37.682 39.568 42.277 40.591 43.947 52.917 10
identical(a2, run)
#[1] TRUE