Ich habe ein einfaches dynamisches Programmierbeispiel beschrieben here, mit data.table, in der Hoffnung, dass es so schnell wie vektorisierter Code sein würde. Voraussetzung für s
und a
, zukünftige Werte von s
(s_next
) gilt als einer der a:(a+10)
, die jeweils mit einer Wahrscheinlichkeit von p=1/(B + 1)
realisiert:Aktualisieren einer data.table Spalte sequentiell mit Schleife
library(data.table)
B=100; M=50; alpha=0.5; beta=0.9;
n = B + M + 1
m = M + 1
u <- function(c)c^alpha
dt <- data.table(s = 0:(B+M))[, .(a = 0:min(s, M)), s] # State Space and corresponging Action Space
dt[, u := (s-a)^alpha,] # rewards r(s, a)
dt <- dt[, .(s_next = a:(a+B), u = u), .(s, a)] # all possible (s') for each (s, a)
dt[, p := 1/(B+1), s] # transition probs
# s a s_next u p
# 1: 0 0 0 0 0.009901
# 2: 0 0 1 0 0.009901
# 3: 0 0 2 0 0.009901
# 4: 0 0 3 0 0.009901
# 5: 0 0 4 0 0.009901
# ---
#649022: 150 50 146 10 0.009901
#649023: 150 50 147 10 0.009901
#649024: 150 50 148 10 0.009901
#649025: 150 50 149 10 0.009901
#649026: 150 50 150 10 0.009901
Um einen wenig Inhalt auf meine Frage zu geben. u
Spalte gibt die u(s, a)
für jede Kombination (s, a)
.
- die Anfangswerte
V
(immern by 1
Vektor) für jeden einzelnen Zustands
, GegebenV
Updates nachV[s]=max(u(s, a)) + beta* sum(p*v(s_next))
(Bellman Gleichung). - Maximierung ist wrt
a
, daher[, `:=`(v = max(v), i = s_next[which.max(v)]), by = .(s)]
in der Iteration unten.
Eigentlich gibt es sehr effizient vectorized solution. Ich dachte data.table
Lösung wäre vergleichbar in der Leistung als vektorisierte Ansatz.
Ich weiß, dass der Hauptschuldige ist dt[, v := V[s_next + 1]]
. Ach, ich habe keine Ahnung, wie ich es beheben kann.
# Iteration starts here
system.time({
V <- rep(0, n) # initial guess for Value function
i <- 1
tol <- 1
while(tol > 0.0001){
dt[, v := V[s_next + 1]]
dt[, v := u + beta * sum(p*v), by = .(s, a)
][, `:=`(v = max(v), i = s_next[which.max(v)]), by = .(s)] # Iteration
dt1 <- dt[, .(v[1L], i[1L]), by = s]
Vnew <- dt1$V1
sig <- dt1$V2
tol <- max(abs(V - Vnew))
V <- Vnew
i <- i + 1
}
})
# user system elapsed
# 5.81 0.40 6.25
Zu meiner Bestürzung, die data.table
Lösung ist sogar langsamer als die folgenden äußerst nicht vektorisiert Lösung. Als schlampiger data.table-user muss ich einige data.table
Funktionen vermissen. Gibt es eine Möglichkeit, Dinge zu verbessern, oder data.table
ist nicht für diese Art von Berechnungen geeignet?
S <- 0:(n-1) # StateSpace
VFI <- function(V){
out <- rep(0, length(V))
for(s in S){
x <- -Inf
for(a in 0:min(s, M)){
s_next <- a:(a+B) # (s')
x <- max(x, u(s-a) + beta * sum(V[s_next + 1]/(B+1)))
}
out[s+1] <- x
}
out
}
system.time({
V <- rep(0, n) # initial guess for Value function
i <- 1
tol <- 1
while(tol > 0.0001){
Vnew <- VFI(V)
tol <- max(abs(V - Vnew))
V <- Vnew
i <- i + 1
}
})
# user system elapsed
# 3.81 0.00 3.81
Siehe https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example. Jemand mag Zeit finden, dieses Chaos zu entwirren, aber die Reduzierung auf die einfachste Demonstration des Problems (in Ihrem Fall eine langsame Verwendung von data.table) wird bessere Ergebnisse von uns bringen. –
@JackWasey Sie haben wirklich Nerven dort. Glauben Sie wirklich, dass diese Verbindung benötigt wird? Ich denke, Khashaa kennt r/data.table nicht schlechter als Sie und weiß, wie man einen MWE auch erstellt. Wenn Sie nicht helfen können, können Sie einfach weitermachen - keine Notwendigkeit in eingebildeten Kommentaren. –
Wenn die Hauptfrage Ihrer Frage darin besteht, wie Sie die Leistung einer data.table-Methode verbessern können, kann vielleicht jemand anderes helfen. Aber wenn Sie nur allgemein nach Wegen suchen, um die Leistung dieser Arten von dynamischen Modellen zu verbessern, dann benutze ich immer RCpp für diese Art von Sache. Die Vektorisierung dynamischer Modelle ist normalerweise schwierig und häufig unmöglich. RCpp ist oft die beste Alternative, wenn Geschwindigkeit benötigt wird. – dww