webentwicklung-frage-antwort-db.com.de

Summe über mehrere Spalten mit dplyr

Meine Frage beinhaltet das Summieren von Werten über mehrere Spalten eines Datenrahmens und das Erstellen einer neuen Spalte, die dieser Summation entspricht, mit dplyr. Die Dateneinträge in den Spalten sind binär (0,1). Ich denke an ein zeilenweises Analog der summarise_each- oder mutate_each-Funktion von dplyr. Hier ist ein minimales Beispiel für den Datenrahmen:

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

Ich könnte so etwas verwenden:

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

dazu müssten jedoch die Namen der einzelnen Spalten geschrieben werden. Ich habe wie 50 Spalten . Außerdem ändern sich die Spaltennamen bei verschiedenen Iterationen der Schleife, in der ich diese .__-Operation implementieren möchte.

Wie kann ich das am effizientesten tun? Jede Hilfe wäre sehr dankbar. 

60
amo

Wie wäre es mit

summiere jede Spalte

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

summiere jede Reihe

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

Ich würde regulären Ausdruck verwenden, um Variablen mit bestimmten Musternamen zu summieren. Zum Beispiel:

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

Auf diese Weise können Sie mehr als eine Variable als Summe bestimmter Variablengruppen Ihres Datenrahmens erstellen.

22
Erick Chacon

Wenn Sie nur bestimmte Spalten zusammenfassen möchten, würde ich Folgendes verwenden:

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)

Auf diese Weise können Sie die Syntax von dplyr::select verwenden.

18
Richard DiSalvo

Dieses Problem tritt häufig auf, und der einfachste Weg, dies zu tun, ist die Verwendung der Funktion apply() innerhalb eines mutate-Befehls.

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))

Hier können Sie die Spalten mit den standardmäßigen dplyr-Tricks auswählen (z. B. starts_with() oder contains()). Wenn Sie die gesamte Arbeit mit einem einzigen mutate-Befehl ausführen, kann diese Aktion überall in einem dplyr-Stream von Verarbeitungsschritten erfolgen. Durch die Verwendung der Funktion apply() können Sie die gewünschte Zusammenfassung verwenden, einschließlich der von Ihnen erstellten Zusammenfassungsfunktion. 

Wenn die Idee der Verwendung einer nicht aufgeräumten Funktion nicht ansprechend ist, können Sie die Spalten zusammenfassen, zusammenfassen und das Ergebnis schließlich wieder mit dem ursprünglichen Datenrahmen verknüpfen.

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, . )

Hier habe ich die Funktion starts_with() verwendet, um die Spalten auszuwählen und die Summe zu berechnen. Sie können mit NA-Werten machen, was Sie wollen. Der Nachteil dieses Ansatzes ist, dass er zwar recht flexibel ist, jedoch nicht wirklich in einen dplyr-Stream von Datenbereinigungsschritten passt. 

7

Die Verwendung von reduce() aus purrr ist etwas schneller als rowSums und auf jeden Fall schneller als apply, da Sie das Durchlaufen aller Zeilen vermeiden und die vektorisierten Operationen nur nutzen:

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

Siehe dies für Timings

0
skd