2016-06-09 14 views
2

Diese Frage sollte eine einfache, elegante Lösung, aber ich kann es nicht herausgefunden, so geht es hier:Count Anzahl der Werte in der Zeile dplyr

Lassen Sie uns sagen, dass ich die folgenden Daten-Set und ich möchte zählen die Anzahl der 2s in jeder Zeile mit dplyr.

set.seed(1) 
ID <- LETTERS[1:5] 
X1 <- sample(1:5, 5,T) 
X2 <- sample(1:5, 5,T) 
X3 <- sample(1:5, 5,T) 

df <- data.frame(ID,X1,X2,X3) 
library(dplyr) 

Nun werden die folgenden Werke:

df %>% 
    rowwise %>% 
    mutate(numtwos = sum(c(X1,X2,X3) == 2)) 

Aber wie vermeide ich die Eingabe alle Spaltennamen aus?

Ich weiß, dass dies wahrscheinlich einfacher ist, ohne dplyr, aber im Allgemeinen möchte ich wissen, wie ich mutatemutate mit mehreren Spalten verwenden kann, ohne alle Spaltennamen eingeben.

Antwort

7

Versuchen rowSums:

> set.seed(1) 
> ID <- LETTERS[1:5] 
> X1 <- sample(1:5, 5,T) 
> X2 <- sample(1:5, 5,T) 
> X3 <- sample(1:5, 5,T) 
> df <- data.frame(ID,X1,X2,X3) 
> df 
    ID X1 X2 X3 
1 A 2 5 2 
2 B 2 5 1 
3 C 3 4 4 
4 D 5 4 2 
5 E 2 1 4 
> rowSums(df == 2) 
[1] 2 1 0 1 1 

Alternativ mit dplyr:

> df %>% mutate(numtwos = rowSums(. == 2)) 
    ID X1 X2 X3 numtwos 
1 A 2 5 2  2 
2 B 2 5 1  1 
3 C 3 4 4  0 
4 D 5 4 2  1 
5 E 2 1 4  1 
+0

Ich erwähnte, dass ich speziell wissen möchte, wie man das mit dplyr macht, auch wenn es nicht die beste Lösung ist. –

+0

@C_Z_ sehe meine neueste Bearbeitung, ich denke, es ist die kürzeste 'dplyr' Lösung –

+1

Interessante Weise .... herum. :) – Gopala

2

Ein Ansatz ist eine Kombination aus dplyr und tidyr zu verwenden, um Daten in langen Format zu konvertieren, und führen Sie die Berechnung:

library(dplyr) 
library(tidyr) 
df %>% 
    gather(key, value, -ID) %>% 
    group_by(ID) %>% 
    summarise(numtwos = sum(value == 2)) %>% 
    inner_join(df, .) 

Ausg t ist wie folgt:

ID X1 X2 X3 numtwos 
1 A 2 5 2  2 
2 B 2 5 1  1 
3 C 3 4 4  0 
4 D 5 4 2  1 
5 E 2 1 4  1 
1

Sie do verwenden können, die nicht die Spalte zu Ihrer ursprünglichen Datenrahmen hinzufügt und Sie müssen die Spalte zu Ihrem ursprünglichen Datenrahmen hinzuzufügen.

df %>% 
    rowwise %>% 
    do(numtwos = sum(.[-1] == 2)) %>% 
    data.frame 
    numtwos 
1  2 
2  1 
3  0 
4  1 
5  1 

eine cbind Fügen Sie die neue Spalte auf den ursprünglichen Datenrahmen zu binden:

df %>% 
    rowwise %>% 
    do(numtwos = sum(.[-1] == 2)) %>% 
    data.frame %>% cbind(df, .) 

    ID X1 X2 X3 numtwos 
1 A 2 5 2  2 
2 B 2 5 1  1 
3 C 3 4 4  0 
4 D 5 4 2  1 
5 E 2 1 4  1 
+0

Danke, ich hatte gehofft, 'dplyr' hatte einen saubereren Weg, dies zu tun. Naja! –

+0

Zeilenweise Operation ist immer irgendwie schmerzhaft, sowohl in 'dplyr' als auch in' data.table', da die Daten spaltenweise aus meinem Verständnis gespeichert werden. – Psidom

+0

@Arun, Danke für die Klärung. Das vermute ich auch. – Psidom

4

Hier ist eine andere Alternative mit purrr:

library(purrr) 

df %>% 
    by_row(function(x) { 
    sum(x[-1] == 2) }, 
    .to = "numtwos", 
    .collate = "cols" 
) 

Welche gibt:

#Source: local data frame [5 x 5] 
# 
#  ID X1 X2 X3 numtwos 
# <fctr> <int> <int> <int> <int> 
#1  A  2  5  2  2 
#2  B  2  5  1  1 
#3  C  3  4  4  0 
#4  D  5  4  2  1 
#5  E  2  1  4  1 

Gemäß der NEWS erwähnt, Reihe basiert Funktionalen reifen noch in dplyr:

Wir sind immer noch herauszufinden, was in dplyr gehört und was gehört in purrr. Erwarten Sie viel Experimentieren und viele Änderungen mit diesen Funktionen.


Benchmark

können wir sehen, wie rowwise() und do()-purrr::by_row() für diese Art von Problem zu vergleichen, und wie sie "perform" gegen rowSums() und die sauberen Daten Art und Weise:

largedf <- df[rep(seq_len(nrow(df)), 10e3), ] 

library(microbenchmark) 
microbenchmark(
    steven = largedf %>% 
    by_row(function(x) { 
     sum(x[-1] == 2) }, 
     .to = "numtwos", 
     .collate = "cols"), 
    psidom = largedf %>% 
    rowwise %>% 
    do(data_frame(numtwos = sum(.[-1] == 2))) %>% 
    cbind(largedf, .), 
    gopala = largedf %>% 
    gather(key, value, -ID) %>% 
    group_by(ID) %>% 
    summarise(numtwos = sum(value == 2)) %>% 
    inner_join(largedf, .), 
    evan = largedf %>% 
    mutate(numtwos = rowSums(. == 2)), 
    times = 10L, 
    unit = "relative" 
) 

Ergebnisse:

#Unit: relative 
# expr   min   lq  mean  median   uq   max neval cld 
# steven 1225.190659 1261.466936 1267.737126 1227.762573 1276.07977 1339.841636 10 b 
# psidom 3677.603240 3759.402212 3726.891458 3678.717170 3728.78828 3777.425492 10 c 
# gopala 2.715005 2.684599 2.638425 2.612631 2.59827 2.572972 10 a 
# evan 1.000000 1.000000 1.000000 1.000000 1.00000 1.000000 10 a 
+3

Das sieht purrrfect –

+1

Purrrfect in der Tat;) Obwohl von den jüngsten Experimenten 'by_row()' ist schmerzhaft langsam für große Datenmenge. –

+1

@ StevenBeaupré cool Vergleich! Danke, dass du das zusammenstellst! –

Verwandte Themen