2014-03-29 1 views
5

Ich möchte einige Preise in verschiedenen Währungen in eine bestimmte Währung umrechnen. ich dies habe Angenommen:In R data.table Multiplikation mit Spaltenname basierend auf Werten einer anderen Spalte

library(data.table) 
set.seed(100) 
DT <- data.table(day=1:10, price=runif(10), currency=c("aud","eur"), 
       aud=runif(10) + 1, eur=runif(10) + 1.5) 
DT 
    day  price currency  aud  eur 
1: 1 0.30776611  aud 1.624996 2.035811 
2: 2 0.25767250  eur 1.882166 2.210804 
3: 3 0.55232243  aud 1.280354 2.038349 
4: 4 0.05638315  eur 1.398488 2.248972 
5: 5 0.46854928  aud 1.762551 1.920101 
6: 6 0.48377074  eur 1.669022 1.671420 
7: 7 0.81240262  aud 1.204612 2.270302 
8: 8 0.37032054  eur 1.357525 2.381954 
9: 9 0.54655860  aud 1.359475 2.049097 
10: 10 0.17026205  eur 1.690291 1.777724 

Der Preis für jeden Tag in der jeweiligen Währung in der Währung Spalte ausgedrückt. So ist 0,30776611 am ersten Tag in AUD (Australische Dollar) und 0,25767250 in EUR (Euro). Die Spalten aud und eur zeigen die Wechselkurse der jeweiligen Währungen in Dollar an. Wie erstelle ich eine neue Preisspalte in Dollar ausgedrückt in einer data.table Weise?

Ich muß mehr price durch die entsprechenden Spaltennamen basierend auf currency, um diese zu erhalten:

DT 
    day  price currency  aud  eur price.in.usd 
1: 1 0.30776611  aud 1.624996 2.035811 0.5001187 
2: 2 0.25767250  eur 1.882166 2.210804 0.5696634 
3: 3 0.55232243  aud 1.280354 2.038349 0.7071682 
4: 4 0.05638315  eur 1.398488 2.248972 0.1268041 
5: 5 0.46854928  aud 1.762551 1.920101 0.825842 
6: 6 0.48377074  eur 1.669022 1.671420 0.8085841 
7: 7 0.81240262  aud 1.204612 2.270302 0.9786299 
8: 8 0.37032054  eur 1.357525 2.381954 0.8820865 
9: 9 0.54655860  aud 1.359475 2.049097 0.7430328 
10: 10 0.17026205  eur 1.690291 1.777724 0.3026789 

Also für den ersten Tag, als ich price * aud = 0.30776611 * 1.624996 multipliziert, weil Preis aud in der currency Spalte war, während auf dem 2. price * eur = 0.25767250 * 2.210804 aus dem gleichen Grund.

Die realen Daten enthalten rund 40 Währungen und damit mehrere ifelse() Erstellen eines Pfeils Anti-Muster sind nicht sehr bequem.

Für den Moment mit einem Substichprobe meiner Daten, ich habe dies:

DT.all[, price := ifelse(curcdd=="AUD", adj.price * AUD, 
         ifelse(curcdd=="BEF", adj.price * BEF, 
           ifelse(curcdd=="BGN", adj.price * BGN, 
            ifelse(curcdd=="CHF", adj.price * CHF, 
              ifelse(curcdd=="CZK", adj.price * CZK, 
                ifelse(curcdd=="DEM", adj.price * DEM, 
                  ifelse(curcdd=="EUR", adj.price * EUR, 
                   ifelse(curcdd=="FRF", adj.price * FRF, 
                     ifelse(curcdd=="GBP", adj.price * GBP, 
                       ifelse(curcdd=="ILS", adj.price * ILS, 
                         ifelse(curcdd=="JPY", adj.price * JPY, 
                          ifelse(curcdd=="NLG", adj.price * NLG, 
                            ifelse(curcdd=="NOK", adj.price * NOK, 
                              ifelse(curcdd=="PLN", adj.price * PLN, 
                                ifelse(curcdd=="SEK", adj.price * SEK, 
                                 ifelse(curcdd=="SGD", adj.price * SGD, 
                                   ifelse(curcdd=="USD", adj.price, NA)))))))))))))))))] 

das, aber es ist nur etwa 20 Währungen und dabei alle von ihnen (~ 40) ist sicherlich nicht elegant wirkt. ..

Vielen Dank!

+0

Ich denke, das wird besser funktionieren, wenn Sie die Preise und Coversion-Tabellen getrennt lassen. Vermutlich hast du die Umrechnungstabellen bekommen und dann nach Datum und Währung zusammengeführt, oder? –

+0

Genau. Ich hatte einen Preis 'data.table' und eine Währung' data.table' und dann habe ich sie mit 'merge (DT, curDT)' zusammengeführt. So erreichen wir dieselbe Tabelle mit: 'DT <- data.table (Tag = 1: 10, Preis = runif (10))', 'currency.DT <- data.table (Tag = 1: 10, Währung = c ("aud", "eur"), aud = Runif (10) + 1, eur = Runif (10) + 1,5) ',' setkey (DT, Tag); setkey (currrency.DT, day) ',' DT <- merge (DT, currency.DT) ' – pidosaurus

Antwort

3

[Bearbeiten] mit der Idee, Arbeits get der Verwendung in Werten von Spaltennamen referenziert zu ziehen, die ich in einer Antwort von Matthew Dowle sah dies scheint wirksam zu sein:

setkey(DT, currency) 
DT[ , cvt := .SD[, get(currency)]*price, by=currency] 
DT 

    day  price currency  aud  eur  cvt 
1: 1 0.30776611  aud 1.624996 2.035811 0.5001188 
2: 3 0.55232243  aud 1.280354 2.038349 0.7071681 
3: 5 0.46854928  aud 1.762551 1.920101 0.8258420 
4: 7 0.81240262  aud 1.204612 2.270302 0.9786301 
5: 9 0.54655860  aud 1.359475 2.049097 0.7430328 
6: 2 0.25767250  eur 1.882166 2.210804 0.5696634 
7: 4 0.05638315  eur 1.398488 2.248972 0.1268041 
8: 6 0.48377074  eur 1.669022 1.671420 0.8085842 
9: 8 0.37032054  eur 1.357525 2.381954 0.8820863 
10: 10 0.17026205  eur 1.690291 1.777724 0.3026789 

Hier ein Verfahren ist, obwohl es doesn ‚t verallgemeinern gut zu größeren Anzahl von Währungen:

DT[ , cvt := ifelse (currency == 'aud', price*aud, price*eur) ] 
> DT 
    day  price currency  aud  eur  cvt 
1: 1 0.30776611  aud 1.624996 2.035811 0.5001188 
2: 2 0.25767250  eur 1.882166 2.210804 0.5696634 
3: 3 0.55232243  aud 1.280354 2.038349 0.7071681 
4: 4 0.05638315  eur 1.398488 2.248972 0.1268041 
5: 5 0.46854928  aud 1.762551 1.920101 0.8258420 
6: 6 0.48377074  eur 1.669022 1.671420 0.8085842 
7: 7 0.81240262  aud 1.204612 2.270302 0.9786301 
8: 8 0.37032054  eur 1.357525 2.381954 0.8820863 
9: 9 0.54655860  aud 1.359475 2.049097 0.7430328 
10: 10 0.17026205  eur 1.690291 1.777724 0.3026789 

Sie erhalten eine Warnung (und andere Ergebnisse, wenn Sie wit versuchen if(.){.}else{.} mit:

DT[ , cvt := if (currency == 'aud'){price*aud}else{price*eur}] 

Dies ist völlig analog zu dem, was mit data.frames passiert. Aber ... mit ifelse in data.table ist bekannt, langsam zu sein.

+0

Vielen Dank für Ihre Antwort. Ich hätte merken sollen, dass ich mehr als 20 Währungen habe, also werde ich meine Frage bearbeiten. – pidosaurus

+0

'get()' ist was ich gesucht habe. Vielen Dank für deine Unterstützung. – pidosaurus

1

Bei dieser Lösung müssen Sie die Anzahl unterschiedlicher Währung angeben (in diesem Fall 2) und die Anzahl der Beobachtungen (in diesem Fall 10), und es wird auch angenommen, dass die Währungswerte ('aud','eur' usw.) zuletzt sind ein paar Spalten.

> B_msk <- matrix(rep(DT$currency,2), ncol=2, byrow=TRUE)==matrix(rep(colnames(DT)[-(1:3)], 10), ncol=2) 
> DF <- data.frame(DT) 
> DF$in_USD <- rowSums(DF[colnames(DT)[-(1:3)]]*B_msk*DF$price) 
> DF #or data.table(DF) 
    day  price currency  aud  eur in_USD 
1 1 0.30776611  aud 1.624996 2.035811 0.5001188 
2 2 0.25767250  eur 1.882166 2.210804 0.5696634 
3 3 0.55232243  aud 1.280354 2.038349 0.7071681 
4 4 0.05638315  eur 1.398488 2.248972 0.1268041 
5 5 0.46854928  aud 1.762551 1.920101 0.8258420 
6 6 0.48377074  eur 1.669022 1.671420 0.8085842 
7 7 0.81240262  aud 1.204612 2.270302 0.9786301 
8 8 0.37032054  eur 1.357525 2.381954 0.8820863 
9 9 0.54655860  aud 1.359475 2.049097 0.7430328 
10 10 0.17026205  eur 1.690291 1.777724 0.3026789 

Edit:

Hoffnung diese Lösung löst Speicherproblem, (aber immer noch benötigen, um die Daten in einem data.frame haben)

> Idx=cbind(1:10,match(DT[,currency], colnames(DT))) #replace 10 with the actually np. of obs. 
> DF=data.frame(DT) 
> DF 
    day  price currency  aud  eur 
1 1 0.30776611  aud 1.624996 2.035811 
2 2 0.25767250  eur 1.882166 2.210804 
3 3 0.55232243  aud 1.280354 2.038349 
4 4 0.05638315  eur 1.398488 2.248972 
5 5 0.46854928  aud 1.762551 1.920101 
6 6 0.48377074  eur 1.669022 1.671420 
7 7 0.81240262  aud 1.204612 2.270302 
8 8 0.37032054  eur 1.357525 2.381954 
9 9 0.54655860  aud 1.359475 2.049097 
10 10 0.17026205  eur 1.690291 1.777724 
> DF$price*as.numeric(DF[Idx]) #assign it as 'DF$P_in_USD' 
[1] 0.5001187 0.5696634 0.7071682 0.1268041 0.8258420 0.8085841 0.9786299 0.8820865 0.7430327 0.3026789 
+0

Vielen Dank für Ihre Antwort. Ich mochte es ziemlich, eine Maskenmatrix zu erstellen. Allerdings sind die Beobachtungen so zahlreich (über 1 Million), dass ich Probleme bei der Speicherreservierung habe. :(Ich frage mich, ob es eine Möglichkeit gibt, die entsprechende Spalte basierend auf dem Währungswert in einer 'data.table' Weise zu suchen ... – pidosaurus

+0

Gern geschehen, sehen Sie, ob die neue Lösung in Ihren Arbeitsspeicher passt –

+0

Es passt, danke! '' Data.table() '' 'get()' ist viel schneller. Die Maske Idee ist etwas, das ich nicht vergessen werde. Danke! – pidosaurus

1

Haben Sie darüber nachgedacht einfach über die Währungen looping , Filtern des Hauptdatenrahmens, um nur die Preise in einer bestimmten Währung zu halten, Durchführen der Konvertierung im Datenteil der Teilmenge und schließlich Stapeln aller Währungsdatenrahmen (oder schrittweises Füllen eines Spalte im Hauptdatenrahmen)