1
votes

mutate_at horizontal vs vertical

J'essaie d'appliquer une fonction uniquement sur certaines colonnes en utilisant mutate_at.

Voici les données:

# A tibble: 12 x 14
# Groups:   LoB [1]
   LoB      AY    R_0    R_1   R_2   R_3   R_4   R_5   R_6   R_7   R_8   R_9  R_10  R_11
   <fct> <dbl>  <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1 1      1994  50135  76631 28763     0 16433  6301     0     0     0     0     0     0
 2 1      1995  96665  81539 31397  1409 16433  6301     0     0     0     0     0     0
 3 1      1996 134960 111966 31771  1879 16869  6301     0     0     0     0     0     0
 4 1      1997 146993 116234 31771  1879 16869  6301     0     0     0     0     0     0
 5 1      1998 160325 118228 31987  2082 17071  6480   147   135     0     0     0     0
 6 1      1999 195389 166654 31987  2082 19186  6480   147   135     0     0     0     0
 7 1      2000 211084 171239 32542  2082 19186  6480   147   135     0     0     0     0
 8 1      2001 252311 186817 32542  2082 19186  6480   147   135     0     0     0     0
 9 1      2002 340671 194929 39703  2082 19186  6663   147   135     0     0     0     0
10 1      2003 370171 225874 41895  3638 20457  7715  1129  1042   902   833   800   684
11 1      2004 400329 234015 41895  3638 20457  7715  1129  3398   902   833   800   684
12 1      2005 447918 245609 42667  4313 20992  7715  1129  3398   902   833   800   684

qui ressemble à ce qui suit:

XXX

Disons que je voudrais créer une somme cumulée de la colonne qui commence par R_ . Pour ce faire, j'ai écrit:

df %>% mutate_at(vars(contains("R_")), funs(cumsum))

qui me donne le résultat suivant:

# A tibble: 12 x 14
# Groups:   LoB [1]
  LoB      AY   R_0   R_1   R_2   R_3   R_4   R_5   R_6   R_7   R_8   R_9  R_10  R_11
  <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1 1      1994 50135 76631 28763     0 16433  6301     0     0     0     0     0     0
 2 1      1995 46530  4908  2634  1409     0     0     0     0     0     0     0     0
 3 1      1996 38295 30427   374   470   436     0     0     0     0     0     0     0
 4 1      1997 12033  4268     0     0     0     0     0     0     0     0     0     0
 5 1      1998 13332  1994   216   203   202   179   147   135     0     0     0     0
 6 1      1999 35064 48426     0     0  2115     0     0     0     0     0     0     0
 7 1      2000 15695  4585   555     0     0     0     0     0     0     0     0     0
 8 1      2001 41227 15578     0     0     0     0     0     0     0     0     0     0
 9 1      2002 88360  8112  7161     0     0   183     0     0     0     0     0     0
10 1      2003 29500 30945  2192  1556  1271  1052   982   907   902   833   800   684
11 1      2004 30158  8141     0     0     0     0     0  2356     0     0     0     0
12 1      2005 47589 11594   772   675   535     0     0     0     0     0     0     0

Le problème ici est que la somme cumulée a été faite verticalement (par variable) plutôt qu'horizontalement. Comment puis-je y parvenir dans dplyr?


0 commentaires

3 Réponses :


3
votes

Je ne suis pas sûr qu'il existe un moyen de le faire sans utiliser rassembler et spread . Voici comment je le ferais. Tout d'abord, je remodelerais les données pour qu'elles soient «longues», puis nous devons utiliser group_by afin que nous ne calculions que le cumsum pour chaque ligne du data.frame (si ce n'est pas suffisamment groupé, nous pouvons ajouter un row_number aux données, et group_by cela). Après cela, nous mutons puis répandons pour que les données redeviennent «larges». Enfin, nous ajoutons un select (names (df)) comme suggéré par @Gregor pour conserver l'ordre d'origine des colonnes.

df %>%
    gather(variable, value, contains('R_')) %>% # reshape wide to long
    group_by(LoB, AY) %>% # group by for each row in original data
    mutate(value = cumsum(value)) %>% # calculate cumsum
    spread(variable, value) %>% # reshape back from long to wide
    select(names(df)) # added to retain original column order

#   LoB      AY   R_0    R_1    R_2    R_3 ...
#   <fct> <dbl> <dbl>  <dbl>  <dbl>  <dbl> ... 
# 1 1      1994 50135 126766 155529 155529 ...
# 2 1      1995 46530  51438  54072  55481 ...
# 3 1      1996 38295  68722  69096  69566 ... 
# 4 1      1997 12033  16301  16301  16301 ...


3 commentaires

Je pense que cela ne calcule pas correctement le cumulé, car l'ordre des lignes après le rassembler ne correspond pas à l'ordre d'origine des colonnes (R_10 vient avant R_2).


Je ne suis pas d'accord. L'ordre des colonnes dans le résultat final est ce qui est différent, pas l'ordre des lignes. Le sperme calcule correctement. Vous pouvez facilement vérifier cela en inspectant les données après la ligne rassembler .


Vrai. Désolé, mon erreur. J'ai supposé que rassembler () trierait les lignes par ordre alphabétique.



2
votes

Réponse similaire à celle du bouncyball, mais elle garde l'ordre des colonnes et utilise un identifiant générique au cas où (LoB, AY) ne serait pas une clé primaire:

df %>% 
  mutate(id = 1:n()) %>% 
  gather(old_name, value, starts_with("R_")) %>% 
  arrange(id, nchar(old_name), old_name) %>% 
  group_by(id) %>% 
  mutate(value = cumsum(value)) %>% 
  ungroup() %>% 
  select(-id) %>% 
  spread(old_name, value) %>% 
  select(names(df)) %>% 
  select(AY, everything())


2 commentaires

En effet, c'est beaucoup plus agréable! J'ai oublié que l'ordre correct est toujours présent dans la variable d'origine. Merci!


avec select (names (df)) , je pense que le select (AY, tout ()) est également redondant



0
votes

Les opérations par ligne fonctionnent souvent mieux sur les matrices. Pour éviter les tracas de rassembler / répandre , j'extraire les colonnes R_ , utiliser apply (conversion implicite en matrice), puis attribuer le résultat retour aux données d'origine:

Cela dit, les données ne semblent pas très ordonnées. Vous feriez peut-être mieux de rassembler le format long et de le conserver longtemps.

result = dd %>% ungroup %>%
  select(starts_with("R_")) %>%
  apply(1, cumsum) %>% 
  t

dd[, grepl("^R_", names(dd))] = result

dd
# # A tibble: 12 x 14
# # Groups:   LoB [1]
#    LoB      AY   R_0    R_1    R_2    R_3    R_4    R_5    R_6    R_7    R_8    R_9   R_10   R_11
#    <fct> <dbl> <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
#  1 1      1994 50135 126766 155529 155529 171962 178263 178263 178263 178263 178263 178263 178263
#  2 1      1995 46530  51438  54072  55481  55481  55481  55481  55481  55481  55481  55481  55481
#  3 1      1996 38295  68722  69096  69566  70002  70002  70002  70002  70002  70002  70002  70002
#  4 1      1997 12033  16301  16301  16301  16301  16301  16301  16301  16301  16301  16301  16301
#  5 1      1998 13332  15326  15542  15745  15947  16126  16273  16408  16408  16408  16408  16408
#  6 1      1999 35064  83490  83490  83490  85605  85605  85605  85605  85605  85605  85605  85605
#  7 1      2000 15695  20280  20835  20835  20835  20835  20835  20835  20835  20835  20835  20835
#  8 1      2001 41227  56805  56805  56805  56805  56805  56805  56805  56805  56805  56805  56805
#  9 1      2002 88360  96472 103633 103633 103633 103816 103816 103816 103816 103816 103816 103816
# 10 1      2003 29500  60445  62637  64193  65464  66516  67498  68405  69307  70140  70940  71624
# 11 1      2004 30158  38299  38299  38299  38299  38299  38299  40655  40655  40655  40655  40655
# 12 1      2005 47589  59183  59955  60630  61165  61165  61165  61165  61165  61165  61165  61165


0 commentaires