Lancer ma [r] réponse dans le chapeau, optimisé pour la vitesse et fonctionne avec n'importe quelle longueur de x (contrairement au demandeur qui était codé en dur pour la longueur 20):
### data
set.seed(100)
x <- round(rnorm(20, sd = 0.02), 3)
### solution
summation <- c(x[1])
enn <- 1
n_of_seq <- c(enn)
for(i in 2:length(x)){
first <- x[i]
second <- summation[i - 1]
if(sign(first) == sign(second)){
summation <- c(summation, first + second)
enn <- enn + 1
}else{
summation <- c(summation, first)
enn <- 1
}
n_of_seq <- c(n_of_seq, enn)
}
Et, pour comparer les temps d'exécution sur mon ordinateur de travail actuel (très lent), voici la sortie de mon microbenchmark en utilisant toutes les solutions R de ce fil. Sans surprise, les solutions réalisant le plus de copies et de conversions étaient généralement plus lentes.
Unit: microseconds
expr min lq mean median uq max neval
my_way() 13.301 19.200 23.38352 21.4010 23.401 20604.0 1e+05
author_way() 19.702 31.701 40.12371 36.0015 40.502 24393.9 1e+05
ronak() 856.401 1113.601 1305.36419 1236.8010 1377.501 453191.4 1e+05
ameer() 388.501 452.002 553.08263 491.3000 548.701 456156.6 1e+05
andrew() 2007.801 2336.801 2748.57713 2518.1510 2760.302 463175.8 1e+05
gonzo() 21.901 35.502 48.84946 43.9010 51.001 29519.5 1e+05
-------------- EDIT -------------- Il a été souligné par @nicola que ma solution n'est pas la plus rapide pour des longueurs de x plus longues - qui devrait être assez évident car je fais continuellement des copies de vecteurs en utilisant des appels comme x <- c (x, y). Je n'ai créé que la solution la plus rapide pour des longueurs = 20 et je n'ai fait que des microparamètres aussi bas que possible pour cela.
Pour faire une comparaison plus juste, j'ai édité toutes les versions pour générer le code original de la manière que je pense serait la plus rapide, mais j'accueille favorablement les commentaires à ce sujet. Voici mon code complet d'analyse comparative et les résultats pour mon système très lent. Je me réjouis de toute rétroaction.
# originally benchmarked a few different lengths
for(pie in c(100000)){
my_way<- function(){
set.seed(100)
x <- round(rnorm(pie, sd = 0.02), 3)
summation <- c(x[1])
enn <- 1
n_of_seq <- c(enn)
for(i in 2:length(x)){
first <- x[i]
second <- summation[i - 1]
if(sign(first) == sign(second)){
summation <- c(summation, first + second)
enn <- enn + 1
}else{
summation <- c(summation, first)
enn <- 1
}
n_of_seq <- c(n_of_seq, enn)
}
# print(summation)
}
author_way <- function(){
set.seed(100)
x <- round(rnorm(pie, sd = 0.02), 3)
sign_indicator <- ifelse(x > 0, 1,-1)
sky <- length(x)
number_of_sequence <- rep(NA, sky)
n <- 1
for (i in 2:sky) {
if (sign_indicator[i] == sign_indicator[i - 1]) {
n <- n + 1
} else{
n <- 1
}
number_of_sequence[i] <- n
}
number_of_sequence[1] <- 1
#############################
summation <- rep(NA, sky)
for (i in 1:sky) {
summation[i] <- sum(x[i:(i + 1 - number_of_sequence[i])])
}
}
# other ppls solutions:
ronak <- function(){
df <- data.table('x' = round(rnorm(pie, sd = 0.02), 3))
df[, c("n_of_sequence", "sum") := list(seq_len(.N), cumsum(x)),rleid(sign(x))]
}
ameer <- function(){
set.seed(100)
x <- round(rnorm(pie, sd = 0.02), 3)
run_lengths <- rle(sign(x))$lengths
n_of_sequence <- run_lengths %>% map(seq) %>% unlist
start <- cumsum(c(1,run_lengths))
start <- start[-length(start)] # start points of each series
map2(start,run_lengths,~cumsum(x[.x:(.x+.y-1)])) %>% unlist()
}
count_and_sum <- function(x){
set.seed(100)
x <- round(rnorm(pie, sd = 0.02), 3)
runs <- rle((x > 0) * 1)$lengths
groups <- split(x, rep(1:length(runs), runs))
output <- function(group) data.frame(x = group, n = seq_along(group), sum = cumsum(group))
result <- as.data.frame(do.call(rbind, lapply(groups, output)))
`rownames<-`(result, 1:nrow(result))
}
andrew <- function(){
set.seed(100)
df <- tibble(x = round(rnorm(pie, sd = 0.02), 3)) %>%
mutate(seqno = cumsum(c(1, diff(sign(x)) != 0))) %>% #identify sequence ids
group_by(seqno) %>% #group by sequences
mutate(n_of_sequence = row_number(), #count row numbers for each group
sum = cumsum(x)) %>% #cumulative sum for each group
ungroup() %>%
select(-seqno)
}
gonzo <- function(){
set.seed(100)
x <- round(rnorm(pie, sd = 0.02), 3)
n_of_sequence <- runner::streak_run(x > 0)
sum <- runner::sum_run(x, k = n_of_sequence)
}
mi1 <- microbenchmark(my_way(), author_way(), ronak(), ameer(), andrew(), gonzo(), times = 10)
print(mi1)
}
Comme ces résultats le montrent, pour d'autres longueurs que celles pour lesquelles j'ai optimisé, ma version est lente. Plus le x est long, plus il se met à ralentir ridiculement pour tout ce qui dépasse 1000. Ma version préférée est celle de Ronak qui n'est que la deuxième plus rapide de mon système. GoGonzo est de loin le plus rapide sur ma machine à ces longueurs plus longues.
Unit: milliseconds
expr min lq mean median uq max neval
my_way() 21276.9027 21428.2694 21604.30191 21581.97970 21806.9543 21896.7105 10
author_way() 82.2465 83.0873 89.42343 84.78315 85.3638 115.4550 10
ronak() 68.3922 69.3067 70.41924 69.84625 71.3509 74.7070 10
ameer() 481.4566 509.7552 521.19034 514.77000 530.1121 579.4707 10
andrew() 200.9654 202.1898 210.84914 206.20465 211.2006 233.7618 10
gonzo() 27.3317 28.2550 28.66679 28.50535 28.9104 29.9549 10
n_of_sequencen'est pas identique à celle souhaitée