web-dev-qa-db-fra.com

Concaténer des chaînes par groupe avec dplyr

j'ai une trame de données qui ressemble à ceci

> data <- data.frame(foo=c(1, 1, 2, 3, 3, 3), bar=c('a', 'b', 'a', 'b', 'c', 'd'))
> data
  foo bar
1   1   a
2   1   b
3   2   a
4   3   b
5   3   c
6   3   d

Je voudrais créer une nouvelle colonne bars_by_foo qui est la concaténation des valeurs de bar par foo. Les nouvelles données devraient donc ressembler à ceci:

  foo bar bars_by_foo
1   1   a          ab
2   1   b          ab
3   2   a           a
4   3   b         bcd
5   3   c         bcd
6   3   d         bcd

J'espérais que ce qui suit fonctionnerait:

p <- function(v) {
  Reduce(f=paste, x = v)
}
data %>% 
  group_by(foo) %>% 
  mutate(bars_by_foo=p(bar))

Mais ce code me donne une erreur

Error: incompatible types, expecting a character vector.

Qu'est-ce que je fais mal?

30
crf

Vous pourriez simplement faire

data %>% 
     group_by(foo) %>% 
     mutate(bars_by_foo = paste0(bar, collapse = "")) 

Sans aucune fonction d'aide

65
David Arenburg

Il semble qu'il y ait un petit problème avec la fonction mutate - J'ai trouvé que c'est une meilleure approche pour travailler avec summarise lorsque vous regroupez des données dans dplyr (ce n'est en aucun cas un règle dure et rapide cependant).

paste, la fonction introduit également des espaces dans le résultat, donc définissez sep = 0 ou utilisez simplement utilisez paste0.

Voici mon code:

p <- function(v) {
  Reduce(f=paste0, x = v)
}

data %>% 
    group_by(foo) %>% 
    summarise(bars_by_foo = p(as.character(bar))) %>%
    merge(., data, by = 'foo') %>%
    select(foo, bar, bars_by_foo)

résultant en ..

  foo bar bars_by_foo
1   1   a          ab
2   1   b          ab
3   2   a           a
4   3   b         bcd
5   3   c         bcd
6   3   d         bcd
4
plumbus_bouquet

Vous pouvez essayer ceci:

agg <- aggregate(bar~foo, data = data, paste0, collapse="")
df <- merge(data, agg, by = "foo", all = T)
colnames(df) <- c(colnames(data), "bars_by_foo") # optional


  # foo bar bars_by_foo
# 1   1     a    ab
# 2   1     b    ab
# 3   2     a     a
# 4   3     b   bcd
# 5   3     c   bcd
# 6   3     d   bcd
3
989

Votre fonction fonctionne si vous vous assurez que la barre est tous des caractères et non des niveaux d'un facteur.

data <- data.frame(foo=c(1, 1, 2, 3, 3, 3), bar=c('a', 'b', 'a', 'b', 'c', 'd'),
stringsAsFactors = FALSE)

library("dplyr")

p <- function(v) {
  Reduce(f=paste, x = v)
 }

data %>% 
  group_by(foo) %>% 
  mutate(bars_by_foo=p(bar))


Source: local data frame [6 x 3]
Groups: foo [3]

   foo   bar bars_by_foo
  <dbl> <chr>       <chr>
    1     1     a     a b
    2     1     b     a b
    3     2     a       a
    4     3     b   b c d
    5     3     c   b c d
    6     3     d   b c d
0
Jim M.