2017-02-22 3 views
0

Dies mag grundlegend sein, aber ich habe versucht, es seit Tagen herauszufinden und habe keine Antwort gefunden.Benutzerdefinierte Funktion basierend auf mehreren Spalten gruppiert nach Kategorie

Ich versuche eine neue Menge basierend auf zwei Spalten "Konzentration" und "Fläche" nach "Einzugsgebiet" zu berechnen. Ich habe eine Funktion geschrieben, um den Unterschied in der Konzentration für jede Zeile und die Zeile mit der größten Fläche nach Flächenanteil in diesem Einzugsgebiet zu berechnen, aber es funktioniert nicht mit dplyr oder aggregate (. Es funktioniert gut mit, aber dann gibt eine Liste

Idealerweise möchte ich eine Spalte auf den Datenrahmen addieren oder die Konzentration Spalte ganz ersetzen Hier ist die Datenrahmen ‚lev‘:..

area catchment concentration 
1 1  Yup  2.00000 
2 10  Yup  40.50000 
3 25  Yup  50.82031 
4 35  Yup  50.00000 
5 1  Nope  1.00000 
6 10  Nope  5.00000 
7 25  Nope  40.08333 
8 35  Nope  38.00000 

Hier ist die Funktion:

lever <- function(data=lev, x=data[,"concentration"], y=data[,"area"]){ 
N= which.max(y) 
L = (x - x[N]) * y/max(y) 
return(L)} 

Und hier das gewünschte Ergebnis ist:

area catchment concentration leverage 
1 1  Yup  2.00000 -1.3714286 
2 10  Yup  40.50000 -2.7142857 
3 25  Yup  50.82031 0.5859375 
4 35  Yup  50.00000 0.0000000 
5 1  Nope  1.00000 -1.0571429 
6 10  Nope  5.00000 -9.4285714 
7 25  Nope  40.08333 1.4880952 
8 35  Nope  38.00000 0.0000000 

Mit by ich zwei Listen mit den Ergebnissen für jeden Einzug bekommen:

by(lev, lev$catchment, lever) 

aber ich mag verwenden, um die Funktion auf mehreren Spalten kategorisierten durch mehrere Faktoren (z Datum neben Einzug) und ich

'falsche Anzahl von Dimensionen'

Fehler mit doBy und dplyr.

+0

Wir können bessere Antworten geben, wenn Sie ein [reproduzierbares Beispiel] bereitstellen (http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example/5965451#5965451). –

+0

Danke für die Bearbeitung, um es reproduzierbar zu machen. Ich werde es nächstes Mal besser machen :) – benjabiker

Antwort

1

Laden Sie Ihre Daten:

lev <- read.table(text = "area catchment concentration 
    1  Yup  2.00000 
    10  Yup  40.50000 
    25  Yup  50.82031 
    35  Yup  50.00000 
    1  Nope  1.00000 
    10  Nope  5.00000 
    25  Nope  40.08333 
    35  Nope  38.00000", 
    header=TRUE) 

von Einzug gruppierte

library(dplyr) 
lev %>% 
    group_by(catchment) %>% 
    mutate(N = which.max(area), 
      L = (concentration - concentration[N]) * area/max(area)) 

# 
# area catchment concentration  N   L 
# <int> <fctr>   <dbl> <int>  <dbl> 
# 1  1  Yup  2.00000  4 -1.3714286 
# 2 10  Yup  40.50000  4 -2.7142857 
# 3 25  Yup  50.82031  4 0.5859357 
# 4 35  Yup  50.00000  4 0.0000000 
# 5  1  Nope  1.00000  4 -1.0571429 
# 6 10  Nope  5.00000  4 -9.4285714 
# 7 25  Nope  40.08333  4 1.4880929 
# 8 35  Nope  38.00000  4 0.0000000 

Ihre Funktion Mit

ich Ihre Funktion ändern, damit es einen Datenrahmen zurück.

lever2 <- function(data, 
        x = data[,"concentration"][[1]], 
        y = data[,"area"][[1]]){ 
    # Use [[1]] to extract the vector only 
    N <- which.max(y) 
    L <- (x - x[N]) * y/max(y) 
    # Put L back into the data frame 
    # so that we keep the concentration and area in the result 
    data$L <- L 
    return(data) 
    } 

Die funtion kann dann mit dplyr::group_by %>% do

lev %>% 
    group_by(catchment) %>% 
    do(lever2(.)) 
+0

Ja, ich schrieb zur gleichen Zeit auf meinem Laptop, aber ich bin langsamer als du. Ich habe ein Beispiel mit der OP-Funktion 'hebel' und dem' group_by'%>% 'do'-Mechanismus hinzugefügt, aber irgendwie kann dieses' 'request''-Objekt nicht gezwungen werden,'double' zu schreiben. Ich muss noch herausfinden wie man dieses eine Arbeit macht. –

+0

Funktioniert perfekt! Wenn ich mehrere Spalten habe (z. B. concentration1, concentration2), wie könnte ich das L für jeden in den Datenrahmen einfügen? – benjabiker

+0

Bearbeiten Sie die 'muate' Anweisung' L = (Konzentration2 - Konzentration2 [N]) * Fläche/max (Fläche) '. Wenn Sie jedoch eine breite Datenstruktur haben, können Sie den Datenrahmen mit [tidyr :: gather] in ein langes Format umformen (ftp://cran.r-project.org/pub/R/web/packages/tidyr/ vignettes/tidy-data.html) vor dem Ausführen der Mutate. –

1

Wir verwenden tidyverse

library(tidyverse) 
df1 %>% 
    group_by(catchment) %>% 
    mutate(leverage = (concentration- concentration[which.max(area)]) * area/max(area)) 

Basierend auf der Beschreibung, wenn es mehr Spalten als variable Gruppierung, die in den group_by platzieren, und die Berechnung kann auch auf mehrere Spalten mit mutate_each angewandt werden

1

Sie auch data.table diesen Wert berechnen verwenden können verwendet werden:

library(data.table) 
# convert to data.table 
setDT(df) 

df[, leverage := (concentration - concentration[which.max(area)]) * (area/max(area)), 
    by=catchment] 
df 
    area catchment concentration leverage 
1: 1  Yup  2.00000 -1.3714286 
2: 10  Yup  40.50000 -2.7142857 
3: 25  Yup  50.82031 0.5859357 
4: 35  Yup  50.00000 0.0000000 
5: 1  Nope  1.00000 -1.0571429 
6: 10  Nope  5.00000 -9.4285714 
7: 25  Nope  40.08333 1.4880929 
8: 35  Nope  38.00000 0.0000000 

Daten

df <- 
structure(list(area = c(1L, 10L, 25L, 35L, 1L, 10L, 25L, 35L), 
    catchment = structure(c(2L, 2L, 2L, 2L, 1L, 1L, 1L, 1L), .Label = c("Nope", 
    "Yup"), class = "factor"), concentration = c(2, 40.5, 50.82031, 
    50, 1, 5, 40.08333, 38)), .Names = c("area", "catchment", 
"concentration"), class = "data.frame", row.names = c("1", "2", 
"3", "4", "5", "6", "7", "8")) 
Verwandte Themen