Suppose I have a data.table where each row consists of two vectors:
The pre-subtraction is the left-half most column and the post- is the right-most columns, with the suffix "prm" at the end.
For example:
#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]
The data:
> 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
A LIFO vector must decrease element-wise to the right before affecting more-left elements. The first row VIOLATES LIFO because
(2, 9, 0) --> (0, 9, 0)
should have subtracted the 2 from the 9 before the 2 on the left-most unit.
I would like to subset to include ONLY the rows that have the 'prm' columns as LIFO subtractions of the non prm columns. E.g.
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
EDIT:
LIFO (last-in-first-out) and FIFO (first-in-first-out) are ways of subtraction that prioritize certain elements.
Consider a vector of numbers, (a,b,c). Consider "c" to be the most recent and "a" to be the least recent.
The total number of units in this vector is a+b+c.
If we subtract d units from it, under LIFO or FIFO subtraction, we do not subtract d from every element, rather, we subtract it elementwise from the most recent (LIFO) or least recent (FIFO), until it is depleted (with a min of 0).
for example
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)
Here is a possible approach to calculate the lifo vector first before filter for those rows with lifo vectors:
#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]
]
output:
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
data:
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"
))
To reiterate the approach from @chinsoon12 and @MichaelChirico in the comments:
Here is 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]], ]
Here is the output:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With