R 我需要实现FIFO算法

R 我需要实现FIFO算法,r,dataframe,fifo,R,Dataframe,Fifo,我有一个数据框,如: items = data.frame( Items = c('Item A', 'Item B','Item A','Item A','Item A','Item B','Item B','Item A','Item C'), Quantity = c(5,100,4,7,10,50,30,1,1000), BuySell = c('B','B','B','S','B','S','S','S','B'), Price = c(100,50,110,130,9

我有一个数据框,如:

items = data.frame(
  Items = c('Item A', 'Item B','Item A','Item A','Item A','Item B','Item B','Item A','Item C'),
  Quantity = c(5,100,4,7,10,50,30,1,1000),
  BuySell = c('B','B','B','S','B','S','S','S','B'),
  Price = c(100,50,110,130,90,45,60,120,5)
)

items$Value = items$Quantity * items$Price
我需要按名称对项目进行分组,并使用FIFO方法计算余额的金额和价值。当我们销售商品时,我们首先按日期销售(表按操作日期分组)。我们需要计算未售出物品的价值

我需要通过FIFO(先进先出)获得移动项目(购买和出售)的结果及其价值

在我的示例中,结果必须是:


首先,将数量列转换为包含买入/卖出的正/负数量:

items$Quantity <- items$Quantity * ifelse(items$BuySell=="B",1,-1)
接下来,我们将其包装成一个函数,以便我们可以通过数据帧的子集调用它:

calculate.lv <- function(x){

    unsold <- sum(x$Quantity)
    x <- x[seq(nrow(x),1,-1),]  # reverse order (unsold items are at bottom)
    x <- x[x$Quantity > 0,]     # consider buy only
    x$cs <- cumsum(x$Quantity)  # cummulative bought amount
    x$cs <- pmin(x$cs, unsold)
    if(nrow(x) > 1) x[-1,"cs"] <- diff(x$cs)    # cs column now holds the amount relevant for cost calculation
    
    list("Quantity" = unsold, "Value" = sum(x$cs * x$Price))
}

calculate.lv(items[items$Items=="Item C",])
#$Quantity
#[1] 1000
#
#$Value
#[1] 5000
by(items, list(items$Items), calculate.lv)
#: Item A
#$Quantity
#[1] 11
#
#$Value
#[1] 1010
#
#------------------------------------------------------------ 
#: Item B
#$Quantity
#[1] 20
#
#$Value
#[1] 1000
#
#------------------------------------------------------------ 
#: Item C
#$Quantity
#[1] 1000
#
#$Value
#[1] 5000
#

使用
dplyr
tidyr
的另一个选项是

library(dplyr)
library(tidyr)

items <- items %>% 
  group_by(Items) %>% 
  mutate(index = 1:n()) %>% 
  spread(BuySell, Quantity, fill = 0) %>% 
  arrange(Items, index) %>% 
  mutate(TotalStock = cumsum(B) - cumsum(S), 
         Sold = case_when(B == 0 ~ 0, # Nothing bought - cannot be sold
                          cumsum(B) < sum(S) ~ B, # Total items bought is smaller than total item sold - everything is sold
                          sum(S) < (cumsum(B) - B) ~ 0, # Total sum is smaller than total amount bought excluding the current buy - nothing sold
                          TRUE ~ B - (cumsum(B) - sum(S))), 
         InStock = B - Sold) 
这可以概括为

items %>% 
  summarize(Value = sum(InStock * Price), 
            TotalStock = sum(InStock))

# A tibble: 3 x 3
#   Items  Value TotalStock
#   <fct>  <dbl>      <dbl>
# 1 Item A  1010         11
# 2 Item B  1000         20
# 3 Item C  5000       1000
项目%>%
汇总(价值=总额(库存*价格),
总库存=总和(库存))
#一个tibble:3x3
#物品价值总存量
#           
#1项目A 1010 11
#2项目B 1000 20
#3项目C 5000 1000

如何获得这些数量/值?例如,
Value 130
来自哪里?与
项目B类似
。。。为什么
数量20
?因为买:(数量)100,卖50+30我在这个例子中看不到任何日期。真的很难遵循你的逻辑。您应该通过编辑您的问题来清楚地解释@Sotos问题的步骤。我们买卖商品(A、B、C项)。买卖以不同的价格进行。当销售以前购买的产品时,该产品将从仓库中扣除。其余货物按剩余货物的购买价格估算。销售首先从同一名称的第一批购货中借记,然后从第二批购货中借记,依此类推。当TotalStock一开始为负数时,有没有办法使其正常工作?我正在处理一个案例,其中a项的初始股票可以是负数(例如,交易中的卖空),但代码却非常出色=)
calculate.lv <- function(x){

    unsold <- sum(x$Quantity)
    x <- x[seq(nrow(x),1,-1),]  # reverse order (unsold items are at bottom)
    x <- x[x$Quantity > 0,]     # consider buy only
    x$cs <- cumsum(x$Quantity)  # cummulative bought amount
    x$cs <- pmin(x$cs, unsold)
    if(nrow(x) > 1) x[-1,"cs"] <- diff(x$cs)    # cs column now holds the amount relevant for cost calculation
    
    list("Quantity" = unsold, "Value" = sum(x$cs * x$Price))
}

calculate.lv(items[items$Items=="Item C",])
#$Quantity
#[1] 1000
#
#$Value
#[1] 5000
by(items, list(items$Items), calculate.lv)
#: Item A
#$Quantity
#[1] 11
#
#$Value
#[1] 1010
#
#------------------------------------------------------------ 
#: Item B
#$Quantity
#[1] 20
#
#$Value
#[1] 1000
#
#------------------------------------------------------------ 
#: Item C
#$Quantity
#[1] 1000
#
#$Value
#[1] 5000
#
library(dplyr)
library(tidyr)

items <- items %>% 
  group_by(Items) %>% 
  mutate(index = 1:n()) %>% 
  spread(BuySell, Quantity, fill = 0) %>% 
  arrange(Items, index) %>% 
  mutate(TotalStock = cumsum(B) - cumsum(S), 
         Sold = case_when(B == 0 ~ 0, # Nothing bought - cannot be sold
                          cumsum(B) < sum(S) ~ B, # Total items bought is smaller than total item sold - everything is sold
                          sum(S) < (cumsum(B) - B) ~ 0, # Total sum is smaller than total amount bought excluding the current buy - nothing sold
                          TRUE ~ B - (cumsum(B) - sum(S))), 
         InStock = B - Sold) 
items
# A tibble: 9 x 9
# Groups:   Items [3]
#   Items  Price Value index     B     S TotalStock  Sold InStock
#   <fct>  <dbl> <dbl> <int> <dbl> <dbl>      <dbl> <dbl>   <dbl>
# 1 Item A   100   500     1     5     0          5     5       0
# 2 Item A   110   440     2     4     0          9     3       1
# 3 Item A   130   910     3     0     7          2     0       0
# 4 Item A    90   900     4    10     0         12     0      10
# 5 Item A   120   120     5     0     1         11     0       0
# 6 Item B    50  5000     1   100     0        100    80      20
# 7 Item B    45  2250     2     0    50         50     0       0
# 8 Item B    60  1800     3     0    30         20     0       0
# 9 Item C     5  5000     1  1000     0       1000     0    1000
items %>% 
  summarize(Value = sum(InStock * Price), 
            TotalStock = sum(InStock))

# A tibble: 3 x 3
#   Items  Value TotalStock
#   <fct>  <dbl>      <dbl>
# 1 Item A  1010         11
# 2 Item B  1000         20
# 3 Item C  5000       1000