2017-01-24 5 views
0

Ich möchte einen gewichteten Durchschnitt aus einem Datenrahmen erstellen und ihn zu einem anderen hinzufügen. Normalerweise mache ich das in SQL, aber ich kann in diesem Fall nicht. Das Beispiel, das ich hier gebe, ist sehr vereinfacht.Berechnung des gewichteten Durchschnitts aus einem Datenrahmen und Hinzufügen einer Spalte zu einem anderen Datenrahmen

Der erste Datenrahmen heißt Kunde. Es hat eine CustomerID-Spalte.

Customer <- data.frame(
    CustomerID = sample(1:10) 
) 

Der zweite Datenrahmen heißt Order. Es hat vier Felder: CustomerID, Year, Weight und TotalCost.

Order <- data.frame(
    CustomerID = sample(1:9, 100, replace=TRUE), 
    Year = sample(2014:2016, 100, replace=TRUE), 
    Weight = sample(1:3, 100, replace=TRUE), 
    TotalCost = sample(200:400, 100, replace=TRUE) 
) 

Ich möchte eine Spalte WeightedCost an den Kunden-Datenrahmen hinzuzufügen, die die gewichtete durchschnittliche Totalcost für den Kunden ist, berechnet Sum (Gewicht * Totalcost)/Sum (Gewicht) durch das Feld Kunden beschränkt und wo das Jahr> 2015.

Ich habe über die Customer-Tabelle geschaut, aber ich bin mir ziemlich sicher, dass es eine bessere vektorisierte Lösung gibt.

Zusätzlich (späte Bearbeitung), würde ich gerne wissen, wie dies zu implementieren, wenn das Jahr aus der Customer-Tabelle kommt, anstatt explizit definiert. Hier ist der neue Kundendatenrahmen:

c = c(1,1,2,2,3,3,4,4,5,5) 
y = c(2014,2015,2014,2015,2014,2015,2014,2015,2014,2015) 
Customer <- data.frame(
    CustomerID = c, 
    Year = y 
) 

Antwort

2

aktualisiert

Keine Ahnung, ob OP noch interessiert ist, aber für die Nachwelt ...

Erstens kann ich sagen, dass, wenn Sie gefragt, die richtige Frage an erster Stelle, und zeigte Ihre gewünschte Leistung, würden Sie wahrscheinlich eine Antwort schneller haben. Zweitens habe ich auf meine erste Antwort zurückgegriffen, weil sie die Frage zumindest so beantwortete, wie sie ursprünglich formuliert war, während spätere Bearbeitungen eindeutig nicht das waren, wonach Sie gesucht hatten.

Antwort

library(dplyr) 
Order %>% 
    filter(Year > 2015) %>% 
    group_by(CustomerID) %>% 
    transmute(w.mean = sum(TotalCost * Weight)/sum(Weight) %>% 
    slice(1) %>% 
    full_join(Customer) 

bearbeiten Rolled zurück - Eingefügt auf Kundendaten

CustomerID  w.mean 
    1   321.5556 
    2   264.3333 
    3   231.2000 
    4   397.0000 
    5   250.0000 
    6   266.6250 
    7   237.0000 
    8   258.2000 
    9   384.8333 
    10   NA 

Ergebnis Aktualisiert Antwort beitreten

Schließlich Ich habe eine neue Reihe von Manipulationen hinzugefügt, die alle gewichteten Kosten von zurück zum angegebenen Jahr hinzufügen. Ich rate immer noch, wie Ihr Ergebnis aussehen soll, aber das ist es, wonach Sie gefragt haben, richtig?

Datenmanipulation

Order %>% 
    group_by(CustomerID, Year) %>% 
    summarize(w.mean = weighted.mean(TotalCost, Weight)) %>% #sum(TotalCost * Weight)/sum(Weight)) %>% 
    arrange(CustomerID, desc(Year)) %>% 
    mutate(w.mean = cumsum(w.mean)) %>% 
    right_join(Customer2, c('CustomerID', 'Year')) 

Ausgabe

CustomerID Year w.mean 
     1 2014 939.3500 
     1 2015 602.3500 
     2 2014 860.7063 
     2 2015 566.9286 
     3 2014 780.8819 
     3 2015 522.4274 
     4 2014 922.6154 
     4 2015 569.6154 
     5 2014 945.9679 
     5 2015 654.7179 

Wenn dies immer noch die falsche Ausgabe ist, und Sie sind immer noch interessiert, bitte ein Beispiel für die korrekte Ausgabe veröffentlichen.

+0

ich mit dem dplyr Paket nicht vertraut bin, obwohl ich es tat installieren und die Bibliothek hinzufügen. Wenn ich Ihren Code in R verbatim einfüge, wird er nicht vollständig. Es sucht nach einer anderen Codezeile. –

+0

Ja, da war eine Klammer am Ende der Transmutationslinie - ich habe sie letzte Nacht bearbeitet, ich schätze, nachdem du sie kopiert hast? - Ich habe es einfach überprüft - sieht jetzt gut aus, tut mir leid :) – user127649

+0

Wie würde ich das implementieren, wenn das Jahr (in diesem Fall: 2015) eine Spalte in der Customer-Tabelle wäre? –

1

Betrachten wir eine Basis R Lösung mit aggregate(), transform() und merge():

# CREATE WEIGHT COST PRODUCT UNIT LEVEL COLUMN 
Order$WgtCostProd <- Order$Weight * Order$TotalCost 

# AGGREGATE WITH NEW WEIGHTEDCOST COLUMN 
OrderAgg <- transform(aggregate(.~CustomerID, Order[Order$Year > 2015,], FUN=sum), 
         WeightedCost = WgtCostProd/Weight) 

# LEFT JOIN MERGE TO ORIGINAL DATAFRAME 
Customer <- merge(Customer, OrderAgg[c("CustomerID", "WeightedCost")], 
        by="CustomerID", all.x=TRUE) 
Customer 

# CustomerID WeightedCost 
# 1   1  302.6667 
# 2   2  281.2941 
# 3   3  229.6667 
# 4   4  308.6000 
# 5   5  305.6667 
# 6   6  315.0000 
# 7   7  312.5833 
# 8   8  333.0000 
# 9   9  295.6667 
# 10   10   NA 
+0

Dies gibt mir eine Spalte WeightedCost.x (CustomerId oder NAN) und WeightedCost.y (WeightedCost) in der Customer-Tabelle . –

+1

Sie verschmelzen kontinuierlich mit * Customer * df. Führen Sie bei jedem Lauf den ersten * Kunden * mit dem Aufruf 'data.frame' erneut aus. Oder erstellen Sie am Ende einen neuen Datenrahmen, anstatt ihn zu überschreiben, wie diese Antwort zeigt. – Parfait

+0

Wie würde ich dies implementieren, wenn das Jahr (in diesem Fall: 2015) eine Spalte in der Customer-Tabelle wäre? –

Verwandte Themen