【问题标题】:Tracing via loop with multiple conditions in R在 R 中通过具有多个条件的循环进行跟踪
【发布时间】:2021-07-29 19:41:55
【问题描述】:

我目前有一个看起来像这样的数据框

Seq<-c(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31)
Direction<-c("IN","IN", "OUT", "IN", "OUT", "IN", "OUT", "OUT", "OUT", "OUT", "IN", "OUT", "OUT", "OUT", "OUT", "OUT", 
             "OUT", "OUT", "OUT", "OUT", "OUT", "OUT", "OUT", "OUT", "IN", "OUT", "OUT", "OUT", "IN", "OUT", "OUT", "OUT")
Amount<-c(0, 3000, 566, 600, 550, 25500,5500, 515, 3500, 3000, 100500, 4000, 515, 25500, 50510, 1560, 5869.43, 4850, 
          15500, 2000, 1367, 3083.41, 3500, 2500, 3000, 3000, 950, 516, 5500, 1500, 3500, 1400)
df<-data.frame(Seq, Direction, Amount)

  Seq Direction    Amount
1    0        IN      0.00
2    1        IN   3000.00
3    2       OUT    566.00
4    3        IN    600.00
5    4       OUT    550.00
6    5        IN  25500.00
7    6       OUT   5500.00
8    7       OUT    515.00
9    8       OUT   3500.00
10   9       OUT   3000.00
11  10        IN 100500.00
12  11       OUT   4000.00
13  12       OUT    515.00
14  13       OUT  25500.00
15  14       OUT  50510.00
16  15       OUT   1560.00
17  16       OUT   5869.43
18  17       OUT   4850.00
19  18       OUT  15500.00
20  19       OUT   2000.00
21  20       OUT   1367.00
22  21       OUT   3083.41
23  22       OUT   3500.00
24  23       OUT   2500.00
25  24        IN   3000.00
26  25       OUT   3000.00
27  26       OUT    950.00
28  27       OUT    516.00
29  28        IN   5500.00
30  29       OUT   1500.00
31  30       OUT   3500.00
32  31       OUT   1400.00

我想创建一个名为 REF 的第四列。 REF所做的可以分为两个想法。在某种程度上,REF 应该选择序列中最早的“IN”并给它编号 1。如果后面有“OUT”,则给它相同的编号。当一个新的“IN”出现时,它给它 2,随后的“OUT”得到 2,所以它继续。但是,REF 还应注意当 OUT 跟随 IN 时还剩下多少,以便跟踪“IN”到来的数量何时会耗尽 - 这就是某些引用最终可能具有多个数字的方式,例如 2,3 ,4 因为直到那时它们才被耗尽。例如,在下面的数据框中,引用为 5 的内容直到第 19 行才被耗尽,其中输出耗尽了先前流入的 100500,然后开始耗尽 4(仍然有 12985 剩余为 25500-5500-515-3500- 3000=12985),导致表示“4,5”。请注意,它是后进先出的,因为它需要首先耗尽最近的流入。例如,它在 (4) 之前耗尽 (5),因为 5 是最近的。这就是为什么它在 2、3、4 之前排 6 以及在第 26 行。

我最终应该拥有的 df 应该是这样的:

  Seq Direction    Amount   REF
1    0        IN      0.00     1
2    1        IN   3000.00     2
3    2       OUT    566.00     2
4    3        IN    600.00     3
5    4       OUT    550.00     3
6    5        IN  25500.00     4
7    6       OUT   5500.00     4
8    7       OUT    515.00     4
9    8       OUT   3500.00     4
10   9       OUT   3000.00     4
11  10        IN 100500.00     5
12  11       OUT   4000.00     5
13  12       OUT    515.00     5
14  13       OUT  25500.00     5
15  14       OUT  50510.00     5
16  15       OUT   1560.00     5
17  16       OUT   5869.43     5
18  17       OUT   4850.00     5
19  18       OUT  15500.00   4;5
20  19       OUT   2000.00     4
21  20       OUT   1367.00     4
22  21       OUT   3083.41     4
23  22       OUT   3500.00     4
24  23       OUT   2500.00     4
25  24        IN   3000.00     6
26  25       OUT   3000.00     6
27  26       OUT    950.00 2;3;4
28  27       OUT    516.00     2
29  28        IN   5500.00     7
30  29       OUT   1500.00     7
31  30       OUT   3500.00     7
32  31       OUT   1400.00     7

我相信带有桶的循环会起作用,但不完全确定应该如何正确设置它。有什么想法吗?

【问题讨论】:

  • 在第 19 行中,Ref 从 5 切换到 4。但是由于 4 还剩 12_985 并且 REF 5 的剩余 OUT 值(包括 15_500 的部分)总和值 > 12_985,为什么不不是切换到 2;3;4 吗?
  • 它是后进先出的,因为它需要首先耗尽最近的流入量 (5),然后是最近的流入量 (4)。这就是为什么它在 2,3,4 之前为 6 以及在第 26 行中
  • 但是 (4) 在 (6) 开始之前已经耗尽。因此,使用您的 LIFO 原则,它必须是 (2;3;4) 在第 22 行(或 21?23?)。
  • 如果你仔细观察的话,4 在 6 之前并没有耗尽:当第 24 行的流出发生时,还有 4 的剩余部分。然后发生 3000 的流入,从 6 开始,但紧接着是 6被价值 3000 的流出耗尽,之后 4 被耗尽。希望这是有道理的

标签: r loops reference trace


【解决方案1】:

部分解决方案

所以我开始想办法解决这个任务,但我没有正确完成。

第一步,我们转换您的数据

df <- data.frame(Seq, Direction, Amount) %>% 
  mutate(Amount = ifelse(Direction == "OUT", -Amount, Amount),
         REF = cumsum(Direction=="IN"),
         control = cumsum(Amount)) %>% 
  group_by(REF) %>% 
  mutate(agg_Amount = cumsum(Amount),
         new_REF    = as.character(REF)) 

得到

# A tibble: 32 x 7
# Groups:   REF [7]
     Seq Direction  Amount   REF control agg_Amount new_REF
   <dbl> <chr>       <dbl> <int>   <dbl>      <dbl> <chr>  
 1     0 IN             0      1      0          0  1      
 2     1 IN          3000      2   3000       3000  2      
 3     2 OUT         -566      2   2434       2434  2      
 4     3 IN           600      3   3034        600  3      
 5     4 OUT         -550      3   2484         50  3      
 6     5 IN         25500      4  27984      25500  4      
 7     6 OUT        -5500      4  22484      20000  4      
 8     7 OUT         -515      4  21969      19485  4      
 9     8 OUT        -3500      4  18469      15985  4      
10     9 OUT        -3000      4  15469      12985  4      
11    10 IN        100500      5 115969     100500  5      
12    11 OUT        -4000      5 111969      96500  5      
13    12 OUT         -515      5 111454      95985  5      
14    13 OUT       -25500      5  85954      70485  5      
15    14 OUT       -50510      5  35444      19975  5      
16    15 OUT        -1560      5  33884      18415  5      
17    16 OUT        -5869.     5  28015.     12546. 5      
18    17 OUT        -4850      5  23165.      7696. 5      
19    18 OUT       -15500      5   7665.     -7804. 5      
20    19 OUT        -2000      5   5665.     -9804. 5      
21    20 OUT        -1367      5   4298.    -11171. 5      
22    21 OUT        -3083.     5   1214.    -14255. 5      
23    22 OUT        -3500      5  -2286.    -17755. 5      
24    23 OUT        -2500      5  -4786.    -20255. 5      
25    24 IN          3000      6  -1786.      3000  6      
26    25 OUT        -3000      6  -4786.         0  6      
27    26 OUT         -950      6  -5736.      -950  6      
28    27 OUT         -516      6  -6252.     -1466  6      
29    28 IN          5500      7   -752.      5500  7      
30    29 OUT        -1500      7  -2252.      4000  7      
31    30 OUT        -3500      7  -5752.       500  7      
32    31 OUT        -1400      7  -7152.      -900  7  

我添加了一个列control,它汇总了Amount 中的所有值。由于control 在第 23 行后变为负数,因此您所有剩余的 REFs 都已耗尽,因此我认为无法完成此任务。

尽管如此,这是第一种方法,也许您可​​以在此基础上进行构建:

# vector for storing the remaining Amount per REF
bucket <- vector()

for (i in seq_len(nrow(df))) {
  pivot_ref <- df$REF[[i]]
  
  if (df$Direction[[i]] == "IN") {
# store the initial Amount in the bucket, bucket index = REF
    bucket[pivot_ref] <- coalesce(bucket[pivot_ref], 0) + df$Amount[[i]]
  } else if (coalesce(bucket[pivot_ref], 0) + df$Amount[[i]] >= 0) {
# if the bucket for the current REF won't be depleted, use this Amount
    bucket[pivot_ref] <- coalesce(bucket[pivot_ref], 0) + df$Amount[[i]]
  } else {
# the hard part
# empty the current bucket and proceed to the bucket with index REF - 1
    amount_remain <- coalesce(bucket[pivot_ref], 0) + df$Amount[[i]]
    
    bucket[pivot_ref] <- 0    
    
    # print(paste("Remaining amount: ", amount_remain))

    while (bucket[pivot_ref] + amount_remain < 0) {    

      pivot_ref <- as.integer(pivot_ref - 1)
# stop condition, if there is nothing left
      if (pivot_ref < 1) {
        # print("Last row:")
        # print(df[i,])
        stop("Bucket empty")
      }
      # print(paste0("pivot_ref ", pivot_ref))
      bucket[pivot_ref] <- bucket[pivot_ref] + amount_remain
      # print(paste0("bucket[pivot_ref] ", bucket[pivot_ref]))
      amount_remain <- coalesce(bucket[pivot_ref], 0) + amount_remain
      # print(paste0("amount_remain ", amount_remain))
      df$new_REF[[i]] <- paste(pivot_ref, df$REF[[i]], sep = ", ")
      # print(paste0("df$new_REF[[i]] ", df$new_REF[[i]]))

    }
  }
  
  print(bucket)
}

这段代码停在22返回的行

# Groups:   REF [7]
     Seq Direction  Amount   REF control agg_Amount new_REF      
   <dbl> <chr>       <dbl> <int>   <dbl>      <dbl> <chr>        
 1     0 IN             0      1      0          0  1            
 2     1 IN          3000      2   3000       3000  2            
 3     2 OUT         -566      2   2434       2434  2            
 4     3 IN           600      3   3034        600  3            
 5     4 OUT         -550      3   2484         50  3            
 6     5 IN         25500      4  27984      25500  4            
 7     6 OUT        -5500      4  22484      20000  4            
 8     7 OUT         -515      4  21969      19485  4            
 9     8 OUT        -3500      4  18469      15985  4            
10     9 OUT        -3000      4  15469      12985  4            
11    10 IN        100500      5 115969     100500  5            
12    11 OUT        -4000      5 111969      96500  5            
13    12 OUT         -515      5 111454      95985  5            
14    13 OUT       -25500      5  85954      70485  5            
15    14 OUT       -50510      5  35444      19975  5            
16    15 OUT        -1560      5  33884      18415  5            
17    16 OUT        -5869.     5  28015.     12546. 5            
18    17 OUT        -4850      5  23165.      7696. 5            
19    18 OUT       -15500      5   7665.     -7804. 4, 5         
20    19 OUT        -2000      5   5665.     -9804. 4, 5         
21    20 OUT        -1367      5   4298.    -11171. 4, 5         
22    21 OUT        -3083.     5   1214.    -14255. 1, 2, 3, 4, 5
23    22 OUT        -3500      5  -2286.    -17755. 5            
24    23 OUT        -2500      5  -4786.    -20255. 5            
25    24 IN          3000      6  -1786.      3000  6            
26    25 OUT        -3000      6  -4786.         0  6            
27    26 OUT         -950      6  -5736.      -950  6            
28    27 OUT         -516      6  -6252.     -1466  6            
29    28 IN          5500      7   -752.      5500  7            
30    29 OUT        -1500      7  -2252.      4000  7            
31    30 OUT        -3500      7  -5752.       500  7            
32    31 OUT        -1400      7  -7152.      -900  7

需要做一些事情:

  • 如果存储桶为空(如本例所示),会发生什么情况?我的代码停在这里。
  • 4, 5 第一次出现是正确的,下一个必须是4。您需要为此找到一个不错的解决方案。
  • 1, 2, 3, 4, 5 实际上必须是 1, 2, 3, 4

【讨论】:

  • 你是对的。没错,它应该在那里缩回 3 和 2。你知道如何写一些东西(一个循环?)来根据这个逻辑产生 REF 吗?
  • 我正在考虑,但工作仍在进行中。我正在考虑将每个 REF 的最终值存储在一个向量中,并使用这些值来创建 REF。但我得再考虑一下。
  • @studentofdata1234 我实际上并没有完成这项任务,但我希望这个部分解决方案可以帮助您进一步前进。
  • 您是否使用了示例数据?
猜你喜欢
  • 2014-12-31
  • 2020-10-17
  • 2022-07-01
  • 2021-12-28
  • 1970-01-01
  • 2023-01-29
  • 2015-02-14
  • 2013-06-30
  • 1970-01-01
相关资源
最近更新 更多