2017-10-31 2 views
0

Ich habe einen Datensatz, der den Preis und die Marktkapitalisierung einer Aktie für einen Datumsbereich enthält. Einige Daten fehlen zwischen dem Datumsbereich. Ich möchte effizient neue Variablen erstellen, die anzeigen, wie stark sich der aktuelle Preis gegenüber dem Preis vor Tagen verändert hat (wobei x eine Liste von Zahlen ist, die Tagesunterschiede darstellen).So erstellen Sie effizient Änderungsvariablen basierend auf dynamischen Datumsdifferenzen in R mit unvollständigen Datumsspalten

Zum Beispiel, ich habe d1:

d1 <- structure(list(Date = c(as.Date("2017-10-28"), as.Date("2017-10-27"), as.Date("2017-10-26"), 
          as.Date("2017-10-24"), as.Date("2017-10-21"), as.Date("2017-10-20")), 
       Price = c(100L, 98L, 102L, 97L, 96L, 100L), 
       MC = c(50L, 55L, 49L, 47L, 50L, 46L)), 
      .Names = c("Date", "Price", "MC")) 

d1<-as.data.frame(d1) 

und mein Wunsch ist d2 (vorausgesetzt, ich bin an 1 und 2 Tagen Änderungen) zu erstellen:

d2 <- structure(list(Date = c(as.Date("2017-10-28"), as.Date("2017-10-27"), as.Date("2017-10-26"), 
          as.Date("2017-10-24"), as.Date("2017-10-21"), as.Date("2017-10-20")), 
       Price = c(100L, 98L, 102L, 97L, 96L, 100L), 
       MC = c(50L, 55L, 49L, 47L, 50L, 46L), 
       Delta1Price = c(0.0204, -0.0392, NA, NA, -0.04, NA), 
       Delta1MC = c(-0.0909, 0.12244, NA, NA, 0.0869, NA), 
       Delta2Price = c(-0.0196, NA, 0.0515, NA, NA, NA), 
       Delta2MC = c(0.0204, NA, 0.04255, NA, NA, NA)), 
      .Names = c("Date", "Price", "MC", "Delta1Price", "Delta1MC", "Delta2Price", "Delta2MC")) 

d2<-as.data.frame(d2) 

wo die Änderungsvariablen berechnet durch (current - previousValue)/PreviousValue

Hier ist meine ineffizienter Weg, dies zu tun, durch die Verwendung einer for-Schleife:

# Assume d1 and d2 are dataframes # 
nms <- colnames(d1)[c(2:3)] 
changeList <- c(1:2) 
for (i in changeList){ 

    #record the dates that will be used to calculate changes 
    currentDate <- d1$Date 
    revDate <- currentDate-i 

    #filter out the rows for the older relevant date 
    revData <- d1 %>% 
     dplyr::filter(d1$Date %in% revDate) 

    #Get the newer dates that are available 
    newCurDate <- revData$Date+i 
    newCurData <- d1 %>% 
    dplyr::filter(d1$Date %in% newCurDate) 

    #calculate the change variables 
    changes <- (newCurData[, nms] - revData[,nms])/revData[,nms] 

    #dynamically name these new change variables 
    newCurData[, paste("Delta", paste(i, nms, sep=""), sep="")]<- changes 

    #merge the data to get desired outcome 
    d1 <- merge(d1, newCurData, all=TRUE) 
} 
#final output should be the same d2 that I structured 
d2 <- d1 

Antwort

0

Zunächst sollten Sie Schleifen in R. nicht vermeiden, dass sie per se schlecht sind, aber die meisten Funktionen akzeptieren Vektoren und sind dafür optimiert, in einer Art und Weise würden Sie wahrscheinlich nicht mit naiven Schleifen erreichen. Und die Dinge werden normalerweise ohne Loops viel einfacher zu lesen.

Zweitens, wenn Sie mit Vektoren arbeiten, haben einige leistungsstarke Pakete eine "Verzögerung" -Methode. Es heißt lag(...) in dplyr, so dass (values - lag(values))/lag(values) die meiste Arbeit erledigen wird; es heißt shift(..., n=1) in data.table.

Drittens können Sie die data.tablerolling joins Vorteile nutzen, die in der Regel mit Datum-Matching erklärt werden. (Diese Funktion ist in dplyr noch nicht implementiert, siehe here.) Habe ich richtig verstanden, dass Sie einen Self-Join durchführen? Dann sollten Sie explizit Datensätze verbinden: d1 %>% left_join(d1) mit dplyr oder d1[d1] in data.table.

Schließlich, warum verwenden Sie keine Pakete für Ihre Aufgabe? Die Rechenrenditen für finanzielle Vermögenswerte scheinen so gemein zu sein, dass ich bezweifle, dass Sie der Einzige sind, der das Problem angeht. Möglicherweise haben Sie mehr Möglichkeiten auf den Aufgabenseiten für finance und time-series.


Ich wickle es auf.

library(datat.table) 
d1 <- data.table(
    Date = as.Date(c("2017-10-28", "2017-10-27", "2017-10-26", "2017-10-24", "2017-10-21", "2017-10-20")), 
    Price = c(100L, 98L, 102L, 97L, 96L, 100L) 
) 
d1[,Date2:=Date] # duplicates the time column, see after 

Das löst das Problem, das ich verstand:

d1[ 
    d1, 
    list(
    Date, Previous_date=Date2, Gap=Date-Date2, 
    Price, Previous_price=i.Price, 
    Return=(Price-i.Price)/i.Price 
    ), 
    on="Date<Date2", 
    mult='first' 
] 

Hier die Erklärung: d1[d1] mit dem data.table Paket eine klassische merge ist. Es gibt viele Möglichkeiten, anzugeben, welche Spalten für die Zusammenführung verwendet werden sollen, aber hier verwende ich on, die On-Th-Fly-Merging-Spalten angibt. Von v1.9.8 ist es möglich, Ungleichungen für die Zusammenführung zu verwenden! Hier gehen wir: on="Date<Date2". Beachten Sie, dass sich die linke Seite auf die erste d1 (vor den Klammern) und die rechte Seite auf die zweite (innerhalb der Klammern) bezieht.

Aber tut so erhalten wir eine viel der Spiele (alle bisherigen Beobachtungen angepasst sind), und wir sind nur in der jüngsten ein Interesse, daher mult='first'.Beachten Sie, dass dazu der Datensatz nach Zeit sortiert sein muss.

Last but not least können wir die Berechnung im laufenden Betrieb durchführen. Alles, was wir in die Ausgabe bekommen wollen, muss in eine list() Anweisung geschrieben werden. Wir können das i. Präfix verwenden, um sich innerhalb der Klammern auf d1 zu beziehen, wie in Previous_price=i.Price. Leider funktioniert dies nicht für die Variablen, die zum Zusammenführen verwendet werden (Date hier), so dass dasselbe Ergebnis wie Date ergibt. Dies ist wahrscheinlich ein Fehler, aber in der Zwischenzeit kopierte ich die Date Spalte vor den Händen, unter dem Namen Date2, die wir zum Beispiel in Gap=Date-Date2 verwenden können.


Ich muß sagen, ich schon gar nicht wie die esoterische data.table Syntax. Aber hier, dplyr hinkt hinterher. Dies sollte jedoch bald abgedeckt werden, it seems.

+0

Danke für die Tipps Arthur. Ich werde die Task-Seite zu Finanzen und Zeitreihen lesen. Ich habe nur einen Self-Join gemacht, um mein Problem zu veranschaulichen, aber ich bin mir nicht sicher, ob das der effizienteste Weg ist. Im Hinblick auf die Lag-Methode habe ich mir vorher einige Beiträge darüber angeschaut, aber es scheint gut zu funktionieren, wenn die Zeitreihe gleichmäßig verteilt ist. In meinem Fall habe ich inkonsistente Zeitreihendaten aufgrund einiger fehlender Daten dazwischen. –

+0

Bearbeitete meine Antwort. Ich gebe zu, es war nicht so einfach ...: D – Arthur

Verwandte Themen