在没有LOOPS或应用的情况下在R中的矩阵上实现基于规则的向量减法(缩减)的有效方式

时间:2016-08-08 00:28:41

标签: r matrix fifo

我不需要使用循环或应用,因为这需要非常有效:

对于那些了解LIFO或FIFO的人,这些是我试图使用的规则。基本上,请考虑以下库存矩阵:

基本上,给定库存矩阵“C”和一些“下降”,“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

此库存矩阵表示有两种产品,每种产品都有两个年份。例如,我们有3个单位的1日龄产品1和2个单元的2日龄产品2.假设我们被告知减去3个单位的产品1。我们可以先从1年级或2年级开始。 LIFO将首先耗尽所有年份1,剩下0单位的1年份和2年份的2年份。先进先出先生将2个单位的2年份,并且因为有一个额外的单位要完成,所以最多可以从年份1,留下葡萄酒2和葡萄酒1的0。

下面,我将展示通常针对许多“下降”实施的此规则(例如,产品1的需求3和单元2中的4将是抽奖的一个示例)。

并且提取:

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

下降的每一行都是一个单独的模拟下降,将使用LIFO或FIFO应用于矩阵。 (LIFO意味着你在满足需求q时首先取消最新的年份(年份2)。而FIFO意味着你走另一条路。)

所以我跑:

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

LIFO的输出应如下所示:

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 个答案:

答案 0 :(得分:1)

以下是您可以尝试使用data.table的矢量化方法:

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
# ...

更新:使用data.table的更通用的解决方案很长,但主要是准备处理数据:

构建一个函数来从向量中减去一个数字,这将耗尽第一个元素,然后是第二个元素,直到数量为零:

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

数据准备:重塑下拉矩阵和库存,将它们绑定在一起进行进一步处理

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)]

通过从每个DrawDraw的广告资源中减去Product值来创建新广告资源,并重新整理结果:

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
# ...