web-dev-qa-db-fra.com

Somme sur plusieurs colonnes avec dplyr

Ma question implique la somme des valeurs sur plusieurs colonnes d'un bloc de données et la création d'une nouvelle colonne correspondant à cette somme à l'aide de dplyr. Les entrées de données dans les colonnes sont binaires (0,1). Je pense à un analogue par rangée de la fonction summarise_each ou mutate_each de dplyr. Vous trouverez ci-dessous un exemple minimal du bloc 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 . En outre, les noms de colonne changent à différentes itérations de la boucle dans laquelle je veux implémenter cette opération Donc j'aimerais essayer d'éviter de devoir donner des noms de colonne.

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

60
amo

Que diriez-vous

résumer chaque colonne

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

résumer chaque ligne

df %>%
   replace(is.na(.), 0) %>%
   mutate(sum = rowSums(.[1:5]))
61
Boern

J'utiliserais la correspondance d'expression régulière pour additionner des variables portant certains noms de modèle. 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 plusieurs variables en additionnant certains groupes de variables de votre trame de données.

22
Erick Chacon

Si vous souhaitez additionner certaines colonnes uniquement, utilisez 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.

18
Richard DiSalvo

Je rencontre souvent ce problème, et le moyen le 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 avoir lieu n'importe où dans un flux d'étapes de traitement dplyr. Enfin, en utilisant la fonction apply(), vous avez la possibilité d’utiliser tout récapitulatif dont vous avez besoin, y compris votre propre fonction de récapitulation construite à cet effet. 

Sinon, si l'idée d'utiliser une fonction non-nid-reverse est peu attrayante, vous pouvez alors rassembler les colonnes, les résumer et finalement joindre le résultat au bloc 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 les valeurs NA. L'inconvénient de cette approche est que, même si elle est assez flexible, elle ne s'intègre pas vraiment dans un flux dplyr d'étapes de nettoyage des données. 

7
Derek Sonderegger

L'utilisation de reduce() à partir de purrr est légèrement plus rapide que rowSums et certainement plus rapide que apply, car vous évitez d'itérer toutes les lignes et vous profitez simplement des opérations vectorisées:

library(purrr)
library(dplyr)
iris %>% mutate(Petal = reduce(select(., starts_with("Petal")), `+`))

Voir ceci pour les horaires

0
skd