2017-01-25 8 views
-1

In dplyr, ich möchte eine Funktion Voraussetzung, dass die Gruppen anwenden, die ich vorher ausgewählt. Die Funktion wird jedoch immer für die vollständigen Daten berechnet. Ein minimales Beispiel:Gruppierung und Funktionen in dplyr

func_a = function(data_a) { 
    value = mean(data_a$V2) 
    return(value) 
} 

data = as.data.frame(cbind(c("a","a","a","b","b","b"), c(1,2,3,4,5,6))) 
data$V2=as.numeric(data$V2) 
data 
V1 V2 
a 1 
a 2 
a 3 
b 4 
b 5 
b 6 
o = data %>% group_by(V1) %>% dplyr::mutate(test = func_a(.)) 

o$test 
[1] 3.5 3.5 3.5 3.5 3.5 3.5 

Ich hätte erwartet/erwünscht:

[1] 2 2 2 5 5 5 

Die mittlere Funktion ist ein einfaches Beispiel, dplyr::mutate(test = mean(V2)) würde die Arbeit tun, klar . Es gibt jedoch andere Funktionen, die nicht so verwendet werden können.

Der Hauptpunkt dieser Frage ist, wie eine Scheibe des Datenrahmens zu einer Funktion zu übertragen, anstatt des Ganzen.

+0

Wie schon geschrieben gibt, gibt es Funktionen, die wie diese werden nicht angewendet, also ja, dann ist es ein Muss. – MaHo

+3

Sie haben Ihre Funktion falsch geschrieben. Es sollte etwas wie 'func_a = function (x) mean (x)' sein und dann könnte man es mit 'data%>% group_by (V1)%>% muate (test = func_a (V2))' oder wenn du willst nennen Es läuft über alle Spalten 'data%>% group_by (V1)%>% mutate_all (Spaß (func_a))' es sei denn, du willst es über 'V2' laufen lassen, ohne es zu sagen? In diesem Fall müssen Sie wahrscheinlich mit 'LazyVal'-Paket herumspielen. –

+0

Danke David, ich kämpfe immer noch ein bisschen mit der Logik davon, aber es funktioniert. Glücklicherweise werde ich Ihre Antwort als Lösung akzeptieren. – MaHo

Antwort

1

Wie @DavidArenburg kommentiert, die Art und Weise Ihre Funktion funktioniert, ist nicht, wie dplyr ausgelegt ist, zu arbeiten. Die . bedeutet explizit die vollständige Variable (data.frame in diesem Fall) durch die %>%. Ich habe diesen Hack gelegentlich verwendet, wenn ich etwas mit den vollständigen Daten machen möchte, und etwas in der Gruppe, z.

data %>% 
    group_by(V1) %>% 
    mutate(eg = mean(V2)/mean(.$V2)) 

 V1 V2  eg 
    <fctr> <dbl>  <dbl> 
1  a  1 0.5714286 
2  a  2 0.5714286 
3  a  3 0.5714286 
4  b  4 1.4285714 
5  b  5 1.4285714 
6  b  6 1.4285714 

gibt daher die beste Lösung mutate zu bekommen die Gruppierung anzuwenden, ist Spaltenname übergeben (s) statt, zB

func_forColumn = function(data_a) { 
    value = mean(data_a) 
    return(value) 
} 

data %>% 
    group_by(V1) %>% 
    mutate(test = func_forColumn(V2)) 

gibt

 V1 V2 test 
    <fctr> <dbl> <dbl> 
1  a  1  2 
2  a  2  2 
3  a  3  2 
4  b  4  5 
5  b  5  5 
6  b  6  5 

Wenn Sie echte Sie müssen in der Lage sein, den vollständigen data.frame zu übergeben (zB arbeiten Sie mit Funktionen, die für ein altes Paradigma geschrieben wurden und können sie aus irgendeinem Grund nicht aktualisieren), Sie könnten entweder split/lapply verwenden, wie ich es von Ihnen gewohnt bin , dann nur bind_rows das Ergebnis, etwa so:

data %>% 
    split(.$V1) %>% 
    lapply(function(x){ 
    x %>% 
     mutate(test = func_a(.)) 
    }) %>% 
    bind_rows() 

die gibt

V1 V2 test 
1 a 1 2 
2 a 2 2 
3 a 3 2 
4 b 4 5 
5 b 5 5 
6 b 6 5 

oder können Sie do verwenden, die etwas komplizierte Gruppierung/Zusammenfassung Ausgänge ermöglicht. Diese ist so konzipiert, mehrspaltigen Rückkehr in data.frames zu ermöglichen, kann aber für Ihr Szenario angepasst werden:

data %>% 
    group_by(V1) %>% 
    do(as.data.frame(func_a(.))) 

gibt

 V1 `func_a(.)` 
    <fctr>  <dbl> 
1  a   2 
2  b   5 

Beachten Sie, dass es nur eine Zeile pro Gruppe zurückgibt. Sie müssten also einen Join (z. B. left_join) zu den Originaldaten verwenden, wenn Sie eine Zeile pro Originaleintrag benötigen.

Hier ist ein typischeres Beispiel für die Verwendung von do, die eher mit dem Grund zusammenhängt, warum Ihre Funktionen einen vollständigen data.frame erwarten.

mySummary <- function(x){ 
    as.data.frame(rbind(summary(x))) 
} 

data %>% 
    group_by(V1) %>% 
    do(mySummary(.$V2)) 

 V1 Min. `1st Qu.` Median Mean `3rd Qu.` Max. 
    <fctr> <dbl>  <dbl> <dbl> <dbl>  <dbl> <dbl> 
1  a  1  1.5  2  2  2.5  3 
2  b  4  4.5  5  5  5.5  6 
Verwandte Themen