Somme sur plusieurs colonnes avec dplyr

Ma question consiste à additionner les valeurs sur plusieurs colonnes d'une trame de données et à créer une nouvelle colonne correspondant à cette sommation en utilisant dplyr. Les entrées de données dans les colonnes sont binaires (0,1). Je pense à un analogue en ligne de la fonction summarise_each ou mutate_each de dplyr. Voici un exemple minimal de la trame de données:

library(dplyr)
df=data.frame(
  x1=c(1,0,0,NA,0,1,1,NA,0,1),
  x2=c(1,1,NA,1,1,0,NA,NA,0,1),
  x3=c(0,1,0,1,1,0,NA,NA,0,1),
  x4=c(1,0,NA,1,0,0,NA,0,0,1),
  x5=c(1,1,NA,1,1,1,NA,1,0,1))

> df
   x1 x2 x3 x4 x5
1   1  1  0  1  1
2   0  1  1  0  1
3   0 NA  0 NA NA
4  NA  1  1  1  1
5   0  1  1  0  1
6   1  0  0  0  1
7   1 NA NA NA NA
8  NA NA NA  0  1
9   0  0  0  0  0
10  1  1  1  1  1

Je pourrais utiliser quelque chose comme:

df <- df %>% mutate(sumrow= x1 + x2 + x3 + x4 + x5)

, Mais cela impliquerait d'écrire les noms de chacune des colonnes. J'ai comme 50 colonnes. Dans en outre, les noms de colonne changent à différentes itérations de la boucle dans laquelle je veux implémenter ceci ainsi, je voudrais essayer d'éviter d'avoir à donner de noms de colonnes.

Comment puis-je le faire le plus efficacement? Toute aide serait grandement appréciée.

47
demandé sur amo 2015-03-05 11:19:33

4 réponses

Que diriez-vous de

Additionnez chaque colonne

df %>%
   replace(is.na(.), 0) %>%
   summarise_all(funs(sum))

Additionnez chaque ligne

df %>%
   replace(is.na(.), 0) %>%
   mutate(sum = rowSums(.[1:5]))
54
répondu Boern 2018-06-18 04:13:00

J'utiliserais la correspondance d'expression régulière pour additionner des variables avec certains noms de motif. Par exemple:

df <- df %>% mutate(sum1 = rowSums(.[grep("x[3-5]", names(.))], na.rm = TRUE),
                    sum_all = rowSums(.[grep("x", names(.))], na.rm = TRUE))

De cette façon, vous pouvez créer plus d'une variable en tant que somme de certains groupes de variables de votre trame de données.

20
répondu Erick Chacon 2017-02-10 23:50:05

Si vous voulez additionner certaines colonnes seulement, j'utiliserais quelque chose comme ceci:

library(dplyr)
df=data.frame(
  x1=c(1,0,0,NA,0,1,1,NA,0,1),
  x2=c(1,1,NA,1,1,0,NA,NA,0,1),
  x3=c(0,1,0,1,1,0,NA,NA,0,1),
  x4=c(1,0,NA,1,0,0,NA,0,0,1),
  x5=c(1,1,NA,1,1,1,NA,1,0,1))
df %>% select(x3:x5) %>% rowSums(na.rm=TRUE) -> df$x3x5.total
head(df)

De cette façon, vous pouvez utiliser la syntaxe de dplyr::select.

16
répondu Richard DiSalvo 2016-04-24 22:36:46

Je rencontre souvent ce problème, et la façon la plus simple de le faire est d'utiliser la fonction apply() dans une commande mutate.

library(tidyverse)
df=data.frame(
  x1=c(1,0,0,NA,0,1,1,NA,0,1),
  x2=c(1,1,NA,1,1,0,NA,NA,0,1),
  x3=c(0,1,0,1,1,0,NA,NA,0,1),
  x4=c(1,0,NA,1,0,0,NA,0,0,1),
  x5=c(1,1,NA,1,1,1,NA,1,0,1))

df %>%
  mutate(sum = select(., x1:x5) %>% apply(1, sum, na.rm=TRUE))

Ici, vous pouvez utiliser ce que vous voulez pour sélectionner les colonnes en utilisant les astuces standard dplyr (par exemple starts_with() ou contains()). En effectuant tout le travail dans une seule commande mutate, cette action peut se produire n'importe où dans un flux dplyr d'étapes de traitement. Enfin, en utilisant la fonction apply(), vous avez la possibilité d'utiliser le résumé dont vous avez besoin, y compris votre propre but construit fonction de résumé.

Alternativement, si l'idée d'utiliser une fonction non-tidyverse n'est pas attrayante, alors vous pouvez rassembler les colonnes, les résumer et enfin joindre le résultat à la trame de données d'origine.

df <- df %>% mutate( id = 1:n() )   # Need some ID column for this to work

df <- df %>%
  group_by(id) %>%
  gather('Key', 'value', starts_with('x')) %>%
  summarise( Key.Sum = sum(value) ) %>%
  left_join( df, . )

Ici, j'ai utilisé la fonction starts_with() pour sélectionner les colonnes et calculer la somme et vous pouvez faire ce que vous voulez avec des valeurs NA. L'inconvénient de cette approche est qu'il est assez souple, il ne rentre pas vraiment dans un dplyr flux de données étapes de nettoyage.

5
répondu Derek Sonderegger 2018-02-26 23:36:10