2016-08-08 49 views
0

Ich brauche keine Schleifen verwenden oder anwenden, da diese sehr effizient sein muss:effiziente Art und Weise regelbasierte Vektor Subtraktion (Drawdown) über Matrizen in R ohne LOOPS zu implementieren oder anwenden

Für diejenigen, die wissen, was LIFO oder FIFO sind, das sind die Regeln, die ich versuche zu verwenden. Grundsätzlich betrachten Sie das folgende Bestandsmatrix:

Grundsätzlich gegebenen eine Bestandsmatrix „C“ und einige „Drawdown“, „qs“:

J=2 
Tp=2 
C = matrix(2,J,Tp) 
rownam = as.character() 
colnam = as.character() 
for(j in 1:J){rownam = c(rownam,paste0('prod',j))} 
for(j in 1:Tp){colnam = c(colnam,paste0('vint',j))} 
rownames(C) = rownam 
colnames(C) = colnam 

C[1,1]=C[1,1]+1 
C[2,1]=C[2,1]-1 

> C 
     vint1 vint2 
prod1  3  2 
prod2  1  2 

Diese Bestandsmatrix gibt es zwei Produkte, die jeweils zwei haben Jahrgänge. Zum Beispiel haben wir 3 Einheiten von 1 Tag altem Produkt 1 und 2 Einheiten von 2 Tage altem Produkt 2. Nehmen wir an, wir sollen 3 Einheiten Produkt1 subtrahieren. Wir könnten es entweder von Jahrgang 1 oder 2 nehmen. LIFO würde es zuerst alle von Jahrgang 1 abschaffen lassen, wobei 0 Einheiten von Jahrgang 1 und 2 Einheiten von Jahrgang 2 übrig bleiben. FIFO würde zuerst die 2 Einheiten von Jahrgang 2 nehmen, und da es eine zusätzliche Einheit gibt, die erfüllt werden muss, geht es weiter Jahrgang 1, 0 von Jahrgang 2 und 2 von Jahrgang 1 verlassend.

Im Folgenden zeige ich diese Regel allgemein für viele "Drawdowns" (zB Nachfrage 3 von Produkt 1 und 4 von Einheit 2 wäre 1 Beispiel für ein Unentschieden)).

Und die Inanspruchnahmen:

qs = rbind(
    c(4, 1), c(4,1), 
    c(4, 1), c(1, 3), 
    c(3, 2), c(4, 1), 
    c(1, 2), c(2, 0), 
    c(2, 1), c(2, 3), 
    c(0, 3), c(2, 2)) 



> qs 
     [,1] [,2] 
[1,] 4 1 
[2,] 4 1 
[3,] 4 1 
[4,] 1 3 
[5,] 3 2 
[6,] 4 1 
[7,] 1 2 
[8,] 2 0 
[9,] 2 1 
[10,] 2 3 
[11,] 0 3 
[12,] 2 2 

Jede Zeile des Verlustes ist ein getrenntes simuliertes drawdown, die auf die Matrix aufgebracht unter Verwendung von LIFO oder FIFO werden soll. (LIFO bedeutet, dass Sie die neuesten Jahrgänge wegzunehmen erste (Jahrgang 2), wenn die Nachfrage q der Befriedigung und FIFO bedeutet, dass Sie in die andere Richtung gehen..)

So betreibe ich:

Cmat = do.call(rbind, replicate(dim(qs)[1], C, simplify=FALSE)) #matrix 

Der Ausgang für die LIFO aussehen sollte so etwas wie dieses:

drawndown 
     vint1 vint2 
prod1  1  0 
prod2  1  1 
prod1  1  0 
prod2  1  1 
prod1  1  0 
prod2  1  1 
prod1  3  1 
prod2  0  0 
... 
+1

Wenn Sie downvote gehen, können Sie mir bitte sagen, wie ich die Frage stellen kann mehr klar ? – robertevansanders

+0

Was bedeuten die Zahlen "0, 1, 2, 3, 4" in der Draw-Down-Matrix? – Psidom

+1

Sie geben an, wie viel von jedem Produkt aus der Inventarmatrix verringert wird, und die Regel gibt an, welche Jahrgänge jedes Produkts zuerst abgerufen werden. – robertevansanders

Antwort

1

ist hier ein vektorisiert Ansatz mit data.table können Sie versuchen:

library(data.table) 
draw_value <- as.vector(t(qs))  # flatten the draw down matrix as a vector 
CmatDT <- data.table(Cmat, keep.rownames = T) # convert the Cmat to data.table 

CmatDT[, `:=` (vint1 = ifelse(vint2 >= draw_value, vint1, vint1 + vint2 - draw_value), 
       vint2 = ifelse(vint2 >= draw_value, vint2 - draw_value, 0))] 
# mutate the vint1 and vint2 columns based on if vint2 contains enough product for the draw down. 

CmatDT 
#  rn vint1 vint2 
# 1: prod1  1  0 
# 2: prod2  1  1 
# 3: prod1  1  0 
# 4: prod2  1  1 
# 5: prod1  1  0 
# 6: prod2  1  1 
# 7: prod1  3  1 
# 8: prod2  0  0 
# ... 

aktualisiert: eine allgemeinere Lösung data.table verwendet, die ziemlich lang ist, aber vor allem ist es, die Daten für die Verarbeitung vorbereitet:

eine Funktion beim Aufbau eine Zahl aus einem Vektor zu subtrahieren, das das erste Element erschöpfen wird und dann die zweite bis die Menge ist Null:

minus <- function(vec, amount) { 
    if(vec[1] >= amount) c(vec[1] - amount, vec[-1]) 
    else c(0, minus(vec[-1], amount - vec[1])) 
} 

Datenvorbereitung: Reshape die draw down-Matrix und Inventar, binden sie zusammen für die weitere Verarbeitung

qsDT <- setNames(data.table(qs, keep.rownames = T), c("DrawId", "Prod1", "Prod2")) 
longQs <- melt(qsDT, id.vars = "DrawId", value.name = "Draw", variable.name = "Product")[order(as.numeric(DrawId))] 
longQsC <- melt(cbind(longQs, C), measure.vars = c("vint1", "vint2"), value.name = "Inventory", variable.name = "Vintage")[order(as.numeric(DrawId), Product, -Vintage)] 

Erstellen Sie das neue Inventar, indem Sie den Draw Wert aus dem Inventar Subtraktion für jeden Draw und Product und umformen das Ergebnis:

longQsC[, NewInventory := minus(Inventory, unique(Draw)), .(DrawId, Product)] 
longQsC[, dcast(.SD, Product ~ Vintage, value.var = "NewInventory"), .(DrawId)] 

# DrawId Product vint1 vint2 
#1:  1 Prod1  1  0 
#2:  1 Prod2  1  1 
#3:  2 Prod1  1  0 
#4:  2 Prod2  1  1 
#5:  3 Prod1  1  0 
#6:  3 Prod2  1  1 
#7:  4 Prod1  3  1 
#8:  4 Prod2  0  0 
# ... 
+1

Können Sie sich vorstellen, wie Sie dies für eine beliebige Anzahl von Jahrgängen lösen würden? Nehmen wir an, wir hätten 3, 4 oder 5? Meine Intuition ist, dass ich eine Reihe-Summen-Summen-Typ-Funktion verwenden müsste – robertevansanders