5 votes

Effectuer des opérations avec décalage sur un cadre de données pour calculer une nouvelle valeur dans R

J'ai le code suivant, je calcule le pourcentage de croissance dans les points de données et ensuite je calcule le changement dans le pourcentage de croissance, ce que je cherche est de pouvoir ajouter une colonne où je compte le nombre de lectures où le changement de croissance est négatif.

df <- data.frame(id = c(1,2,3,4,5,6,7,8,9,10,11,12), data = c(19, 19, 27, 27, 38, 42, 47, 48, 49, 50, 51, 53))
df <- mutate(df, pct_growth = (data - lag(data))/lag(data))
df <- mutate(df, pct_growth_change = pct_growth - lag(pct_growth))
df$pct_growth_streak <- 0
df <- dplyr::mutate(df, pct_growth_streak = ifelse(pct_growth_change <=0, lag(pct_growth_streak)+1,0) )

Ce que j'obtiens comme résultat est le suivant

   id data pct_growth pct_growth_change pct_growth_streak
1   1   19         NA                NA                NA
2   2   19 0.00000000                NA                NA
3   3   27 0.42105263      0.4210526316                 0
4   4   27 0.00000000     -0.4210526316                 1
5   5   38 0.40740741      0.4074074074                 0
6   6   42 0.10526316     -0.3021442495                 1
7   7   47 0.11904762      0.0137844612                 0
8   8   48 0.02127660     -0.0977710233                 1
9   9   49 0.02083333     -0.0004432624                 1
10 10   50 0.02040816     -0.0004251701                 1
11 11   51 0.02000000     -0.0004081633                 1
12 12   53 0.03921569      0.0192156863                 0

Et ce dont j'ai besoin est

   id data pct_growth pct_growth_change pct_growth_streak
1   1   19         NA                NA                NA
2   2   19 0.00000000                NA                NA
3   3   27 0.42105263      0.4210526316                 0
4   4   27 0.00000000     -0.4210526316                 1
5   5   38 0.40740741      0.4074074074                 0
6   6   42 0.10526316     -0.3021442495                 1
7   7   47 0.11904762      0.0137844612                 0
8   8   48 0.02127660     -0.0977710233                 1
9   9   49 0.02083333     -0.0004432624                 2
10 10   50 0.02040816     -0.0004251701                 3
11 11   51 0.02000000     -0.0004081633                 4
12 12   53 0.03921569      0.0192156863                 0

4voto

Ronak Shah Points 24715

Nous pouvons utiliser rleid pour créer des groupes de stries consécutives et calculer cumsum par-dessus.

library(data.table)

setDT(df)[, pct_growth_streak := cumsum(pct_growth_streak), 
            rleid(pct_growth_streak)]

df
#    id data pct_growth pct_growth_change pct_growth_streak
# 1:  1   19         NA                NA                NA
# 2:  2   19 0.00000000                NA                NA
# 3:  3   27 0.42105263      0.4210526316                 0
# 4:  4   27 0.00000000     -0.4210526316                 1
# 5:  5   38 0.40740741      0.4074074074                 0
# 6:  6   42 0.10526316     -0.3021442495                 1
# 7:  7   47 0.11904762      0.0137844612                 0
# 8:  8   48 0.02127660     -0.0977710233                 1
# 9:  9   49 0.02083333     -0.0004432624                 2
#10: 10   50 0.02040816     -0.0004251701                 3
#11: 11   51 0.02000000     -0.0004081633                 4
#12: 12   53 0.03921569      0.0192156863                 0

Nous pouvons l'utiliser dplyr aussi :

library(dplyr)

df %>%
   group_by(grp = rleid(pct_growth_streak)) %>%
   mutate(pct_growth_streak = cumsum(pct_growth_streak))

Ou avec ave :

with(df, ave(pct_growth_streak, rleid(pct_growth_streak), FUN = cumsum))

1voto

drf Points 4318

Une approche : définir d'abord une variable de regroupement sgrp qui s'incrémente à chaque changement de signe de pct_growth_change :

df %<>% mutate(sgrp = cumsum(if_else(sign(pct_growth_change) == 
                               sign(lag(pct_growth_change, 1)), 0, 1, 1)))

Puis regrouper par sgrp et mettre pct_growth_streak comme le numéro de ligne dans le groupe si pct_growth_change est négatif.

df %>% 
group_by(sgrp) %>% 
mutate(pct_growth_streak = 
    (pct_growth_change < 0) * row_number()
) %>%
ungroup() %>%
select(-sgrp);

1voto

hello_friend Points 4356

J'ai utilisé la logique de ce post ( https://stackoverflow.com/a/49051192/9203158 ) merci @missuse :

library(tidyverse)
library(data.table)
df %>% 
  mutate(pct_growth = (data - lag(data))/lag(data), 
         pct_growth_change = pct_growth - lag(pct_growth), 
         streak_change = ifelse(pct_growth_change > 0, -1, 1), 
         is_neg = ifelse(pct_growth_change < 0, 1, 0)) %>%
  group_by(grp = rleid(streak_change)) %>% 
  mutate(pct_growth_streak = streak_change*cumsum(is_neg)) %>% 
  ungroup() %>% 
  select(-c(grp, streak_change, is_neg))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X