如何检查一个向量是否是LIFO/FIFO下降的

8
假设我有一个data.table,每行都由两个向量组成:
  1. 一个“预减法”向量。
  2. 一个“后减法”向量。
其中,左半部分是“预减法”,右半部分是“后减法”,并且在末尾带有“prm”后缀。
例如:
#Sample Data
set.seed(2)
fill = data.table(n=1:7)
Tp=3

  for(t in 1:Tp){ 
     set(x = fill, j = paste0('v',t), value = sample(0:10,7))
  }

fill[1,paste0('v',3):=0]
fill[5,paste0('v',2):=0]
fill[5,paste0('v',3):=0]

for(t in 1:Tp){ 
  fill[,paste0('v',t,'prm'):=get(paste0('v',t))]
}


fill[1,paste0('v',1,'prm'):=0] 
fill[2,paste0('v',2,'prm'):=1]   
fill[5,paste0('v',3,'prm'):=1]  
fill[7,paste0('v',3,'prm'):=2] 

数据:

> fill
   n         v1         v2         v3          v1prm         v2prm        v3prm
1: 1          2          9          0             0             9             0
2: 2          7          4          8             7             1             8
3: 3          5         10          9             5            10             9
4: 4          1          8          1             1             8             1
5: 5          6          0          0             6             0             1
6: 6          8          7          0             8             7             0
7: 7          0          0          6             0             0             2

一个后进先出(LIFO)的向量必须从右往左逐元素递减,然后再影响到更左边的元素。第一行违反了LIFO规则,因为 (2, 9, 0) --> (0, 9, 0) 应该在左侧单元上的2被减去9之前,先从9中减去2。
我希望将子集仅包括prm列作为非prm列的LIFO减法的行。例如:
   n         v1         v2          v3          v1prm         v2prm        v3prm
1: 3          5         10          9             5            10             9
2: 4          1          8          1             1             8             1
3: 6          8          7          0             8             7             0
4: 7          0          0          6             0             0             2       

编辑:

LIFO(后进先出)和FIFO(先进先出)是优先考虑某些元素的减法方式。

考虑一个数字向量(a,b,c)。将“c”视为最近的,将“a”视为最不近的。

这个向量中的单位总数是a+b+c。

如果我们从中减去d个单位,在LIFO或FIFO减法下,我们不会从每个元素中减去d,而是从最近的(LIFO)或最不近的(FIFO)逐个元素地减去,直到它被消耗完(至少为0)。

例如

LIFO: (3,2,1) - 5 = (3,2,1 - 5) --> (3,2 -4 ,0) --> (3 -2 ,0,0) --> (1,0,0)

FIFO: (3,2,1) - 5 = (3-5,2,1) --> (0,2 -2 ,1) --> (0 ,0,1)


@Henrik 有点像,我保留了另一个问题,因为我对一般的动态列比较感兴趣,所以从某种意义上说,这是关于一个特定工具的问题,你可以使用它来完成这个任务。但希望能够找到更有效的方法:\ - wolfsatthedoor
如@MichaelChirico在另一篇帖子中建议的那样,如果您将帖子列重命名为prmprod1vint1prmprod1vint2等,则可以执行以下操作:fill[n %in% melt(fill, measure.vars=patterns("^prod","^prm"))[, !is.unsorted(value1 - value2), by=.(n)][(V1), n]] - chinsoon12
1
这种差异的排序不足以描述Lifo。例如...(6,5,5)到(5,3,1)不是lifo,但满足递增的差异@chinsoon12 - wolfsatthedoor
3
我认为有必要提供更清晰的LIFO定义。 - s_baldur
@snoram 完成了,感谢您的建议。 - wolfsatthedoor
2个回答

5
以下是一种可能的方法,先计算LIFO向量,然后过滤掉那些具有LIFO向量的行:
#convert into long format from MichaelChirico and svenkatesh
tbl <- melt(fill, meas=patterns("^v[1-9]$", "prm$"), 
    value.name=c("bef","aft"))
setorder(tbl, n, -variable)

     #filter for those lifo vector
fill[n %in% 
        tbl[, {
                #calculate stock taken out
                dif <- sum(bef) - sum(aft)

                #calculate lifo vector
                lifo <- pmin(pmax(cumsum(bef) - dif, 0L), bef)

                #check if after is this lifo vector
                identical(lifo, aft)

            }, by=.(n)][(V1), n]
    ]

输出:

   n v1 v2 v3 v1prm v2prm v3prm
1: 3  5 10  9     5    10     9
2: 4  1  8  1     1     8     1
3: 6  8  7  0     8     7     0
4: 7  0  0  6     0     0     2

数据:

library(data.table)
fill <- structure(list(n = 1:7, v1 = c(2L, 7L, 5L, 1L, 6L, 8L, 0L), v2 = c(9L, 
    4L, 10L, 8L, 0L, 7L, 0L), v3 = c(0L, 8L, 9L, 1L, 0L, 0L, 6L), 
    v1prm = c(0L, 7L, 5L, 1L, 6L, 8L, 0L), v2prm = c(9L, 1L, 
        10L, 8L, 0L, 7L, 0L), v3prm = c(0L, 8L, 9L, 1L, 1L, 0L, 2L
        )), row.names = c(NA, -7L), class = c("data.table", "data.frame"
        ))

嗯,我正在尝试解析这个,但是当我运行它时,虽然出现了“空数据表(0行)7列:n,v1,v2,v3,v1prm,v2prm...”,但没有选择任何行。 - wolfsatthedoor
@wolfsatthedoor,出现了类型不匹配的问题(数字与整数)。我已经使用0L代替0进行修复。 - chinsoon12
好的,我明白了,谢谢。你能解释一下{}符号和末尾的V1吗?我觉得我理解其他所有内容,但我没有见过这些简洁的符号。我认为如果再多解释一点,这看起来值得奖励。谢谢! - wolfsatthedoor
花括号用于将多个表达式包装在j参数中,以便可以在每个by组中计算和使用中间计算(例如dif <- sum(bef) - sum(aft))。花括号内的最后一个表达式作为结果返回。 - chinsoon12
1
或许在setorder中移除负号会更容易? - chinsoon12
显示剩余4条评论

2
为了重申@chinsoon12和@MichaelChirico在评论中提出的方法:
以下是“填充(fill)”的示例代码:
   n prod1vint1 prod1vint2 prod1vint3 prod1vint1prm prod1vint2prm prod1vint3prm
1: 1          2          9          0             0             9             0
2: 2          7          4          8             7             1             8
3: 3          5         10          9             5            10             9
4: 4          1          8          1             1             8             1
5: 5          6          0          0             6             0             1
6: 6          8          7          0             8             7             0
7: 7          0          0          6             0             0             2

# Melt so that the data from the "prm" columns are different from the "prod" columns 
d = melt(fill, measure.vars = patterns("int[1-9]$", "prm$"))

# Subtract the vectors and check whether the difference is increasing (LIFO condition)
s = d[, !is.unsorted(value1 - value2), by=.(n)]

# Select the rows that satisfy the LIFO condition 
output = fill[n %in% d[, s[(V1), n]], ]

以下是输出结果:

   n prod1vint1 prod1vint2 prod1vint3 prod1vint1prm prod1vint2prm prod1vint3prm
1: 3          5         10          9             5            10             9
2: 4          1          8          1             1             8             1
3: 6          8          7          0             8             7             0
4: 7          0          0          6             0             0             2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接