2017-09-15 1 views
1

J'essaie de sommer 1 ou plusieurs colonnes de données en donnant une liste de colonnes qui devraient comprendre la sommation.Créer un nombre dynamique de colonnes à partir d'une trame de données, basée sur un vecteur de caractères

Par exemple:

set.seed(3550) 
# Creates data frame 
month <- seq.Date(from = as.Date("2012-09-01"), by = "month", length.out = 50) 
a <- rpois(50, 5000) 
b <- rpois(50, 3000) 
c <- rpois(50, 500) 
d <- rpois(50, 1000) 

df <- data.frame(month, a, b, c, d) 
# Creates list of vectors 
mylist <- list(this = "this", that = "that", other = "other") 
mylist$this <- c("a") 
mylist$that <- c("a", "b") 
mylist$other <- c("a", "c", "d") 

Je peux obtenir des résultats que je veux avec le code suivant:

my_df <- df %>% 
    group_by(month) %>% 
    summarize(this = sum(!!!rlang::syms(mylist$this), na.rm = TRUE), 
      that = sum(!!!rlang::syms(mylist$that), na.rm = TRUE), 
      other = sum(!!!rlang::syms(mylist$other), na.rm = TRUE)) 

Avec l'être de sortie:

# A tibble: 50 x 4 
     month this that other 
     <date> <int> <int> <int> 
1 2012-09-01 4958 7858 6480 
2 2012-10-01 4969 7915 6497 
3 2012-11-01 5012 7978 6483 
4 2012-12-01 4982 7881 6460 
5 2013-01-01 4838 7880 6346 
6 2013-02-01 5090 8089 6589 
7 2013-03-01 5013 8044 6582 
8 2013-04-01 4947 7942 6388 
9 2013-05-01 5065 8124 6506 
10 2013-06-01 5020 8086 6521 
# ... with 40 more rows 

Je rencontre des problèmes en essayant pour comprendre comment créer dynamiquement le nombre de colonnes récapitulatives. Je pensais que boucler à l'intérieur de l'appel de résumé pourrait fonctionner, mais il n'a pas fait.

combine_iterations <- function(x, iter_list){ 
    a <- rlang::syms(names(iter_list)) 
    b <- x %>% 
    group_by(month) %>% 
    summarize(for (i in 1:length(a)){ 
     a[[i]] = sum(!!!rlang::syms(iter_list[i]), na.rm = TRUE) 
    }) 
} 

Sortie:

Error in lapply(.x, .f, ...) : object 'i' not found 
Called from: lapply(.x, .f, ...) 
+1

ce que dans le monde est '!!!'? –

+0

@KyleWeise Il fait partie de la mécanique de devis/unquote qui a été ajouté à dplyr quand les fonctions d'évaluation standard ont été déconseillées. Plus précisément, c'est l'épissure unquote. –

Répondre

2

Vous faites un peu plus compliqué; Si vous voulez personnaliser le summarization, vous pouvez utiliser group_by %>% do et éviter la rlang citation/numéro unquote:

combine_iterations <- function(x, iter_list){ 
    x %>% 
     group_by(month) %>% 
     do(
      as.data.frame(lapply(iter_list, function(cols) sum(.[cols]))) 
    ) 
} 

combine_iterations(df, mylist) 
# A tibble: 50 x 4 
# Groups: month [50] 
#  month this that other 
#  <date> <int> <int> <int> 
# 1 2012-09-01 5144 8186 6683 
# 2 2012-10-01 5134 8090 6640 
# 3 2012-11-01 4949 7917 6453 
# 4 2012-12-01 5040 8203 6539 
# 5 2013-01-01 4971 7938 6474 
# 6 2013-02-01 5050 7924 6541 
# 7 2013-03-01 5018 8022 6579 
# 8 2013-04-01 4945 7987 6476 
# 9 2013-05-01 5134 8114 6590 
#10 2013-06-01 4984 8011 6476 
# ... with 40 more rows 

identical(
    df %>% 
     group_by(month) %>% 
     summarise(this = sum(a), that = sum(a, b), other = sum(a, c, d)), 

    ungroup(combine_iterations(df, mylist)) 
) 
# [1] TRUE 

ou une autre option créer trame de données avec purrr::map_df dans do:

combine_iterations <- function(x, iter_list){ 
    x %>% 
     group_by(month) %>% 
     do({ 
      g = . 
      map_df(iter_list, ~ sum(g[.x])) 
     }) 
} 
+0

J'ai aussi vu votre solution avec purrr: map_df() dedans. Pourquoi est-ce préférable? Juste parce que c'est fait dans la base R? –

+0

En fait, je préfère le 'map_df' pour la concision, mais je pensais que cela pourrait apporter de la confusion. Je l'ajoute comme une deuxième option. – Psidom