Расчет R на основе предыдущих результатов шаг за шагом по группе - PullRequest
0 голосов
/ 28 мая 2020

введите здесь описание изображения Я хочу узнать, сколько дней без припасов и сколько дней с припасами в каждом периоде по группам, я думаю создать новую переменную "Дни" . Сначала я вычислил временной интервал между двумя датами рядом друг с другом «DateDiff», затем я использовал временной интервал «DateDiff», чтобы вычесть предыдущие SupplyDays lag(SupplyDays), чтобы получить «DaysLeft», если DaysLeft> 0, это означает, что есть нехватка предложения, и если DaysLeft <0, это означает, что запас остался, может быть использован в следующие дни. Но это только сравнение с предыдущей строкой, поэтому необходимо проделать больше работы. Звучит сложно. Но моя цель - выяснить, сколько дней без припасов и сколько дней с припасами в каждый период. Дело в том, что в будущем можно использовать только предыдущие оставленные запасы, но будущие оставшиеся запасы нельзя использовать в прошлом, поэтому каждый шаг расчета основан на предыдущем результате, и <code>cumsum() доза не применяется к моим кейс. Первое значение «Дней» каждой группы равно «ДнейLeft». Затем, если предыдущие «Дни» <0, текущие «Дни» должны быть текущими «Дни осталось» плюс предыдущие «Дни», чтобы отменить запасы, оставшиеся от прошлого, если предыдущие «Дни»> 0, настоящее «Days» равно текущему «DaysLeft».

df <- data.frame(Group = c(3, 3, 1, 2, 1, 2, 1, 3, 1, 1), 
                 Date = c(20190102, 20190207, 20190309, 20190417, 20190507, 20190610, 20190707, 20190808, 20190907, 20191018),
                 SupplyDays = c(80,9,40,7,35,7,2,60,1,5))

Я пытался использовать mutate(), но функция mutate не может определить новую переменную, поэтому она не может проверить> 0 или <0 . Затем я создал al oop, но l oop иногда работает, иногда нет. И я не знаю, как group_by в l oop. </p>

df$Days[1] <- df$DaysLeft[1]
for (i in 2:length(df$DaysLeft)){
    if (df$Days[i-1]>=0){
        df$Days[i]<-df$DaysLeft[i]
    } else {
   df$Days[i]<-(df$DaysLeft[i]+df$Days[i-1])
  }
}

Если у вас любые мысли, я был бы очень признателен! Я новичок в R, и я работал над этим несколько дней. Спасибо!

1 Ответ

0 голосов
/ 29 мая 2020

Будет ли это работать для вас:

library(dplyr)
library(tidyr)

df <- df %>%
  arrange(Group) %>% # for convenience
  mutate(Date = as.Date(as.character(Date), "%Y%m%d")) %>% # coerce dates to Date format
  group_by(Group) %>% 
  mutate(DateDiff = Date - lag(Date, 1)) %>% # calculate time difference with previous row
  mutate(DateDiff = replace_na(DateDiff, 0)) %>% # replace NA with 0
  mutate(DaysLeft = DateDiff - lag(SupplyDays,1)) %>%
  mutate(DaysLeft = replace_na(DaysLeft, 0)) %>%  # replace NA with 0
  mutate(Days = ifelse(lag(DaysLeft, 1) < 0, DaysLeft + lag(DaysLeft, 1), DaysLeft)) %>%
  mutate(Days = replace_na(Days, 0)) # replace NA with 0

С этим выводом:

> df
# A tibble: 10 x 6
# Groups:   Group [3]
   Group Date       SupplyDays DateDiff DaysLeft  Days
   <dbl> <date>          <dbl> <drtn>   <drtn>   <dbl>
 1     1 2019-03-09         40   0 days   0 days     0
 2     1 2019-05-07         35  59 days  19 days    19
 3     1 2019-07-07          2  61 days  26 days    26
 4     1 2019-09-07          1  62 days  60 days    60
 5     1 2019-10-18          5  41 days  40 days    40
 6     2 2019-04-17          7   0 days   0 days     0
 7     2 2019-06-10          7  54 days  47 days    47
 8     3 2019-01-02         80   0 days   0 days     0
 9     3 2019-02-07          9  36 days -44 days   -44
10     3 2019-08-08         60 182 days 173 days   129

UPDATE

Я думал об этом на выходных, и это может помочь подойти к этой проблеме иначе. Мы имеем дело с проблемой запасов / потребления, так что вот очень простой подход. У нас должны быть правильные определения, чтобы это работало:

  • Входящие: материалы, поступающие в начале периода. Я полагаю, что ваш SupplyDays именно такой.
  • Потребление: в течение периода мы потребляем один день запасов в день

Нам нужно будет рассчитать запасы в конце каждый период. Итак, я создал немного другой фрейм данных со столбцами Date, Incoming и Inventory. Предполагается, что первая строка - это period: 0 только с существующим инвентарем. Тогда Inventory становится суммой того, что у меня уже есть (data$Inventory [i - 1]), того, что поступает в этот период (data$Incoming[i]), и за вычетом того, что я потребляю (as.numeric(data$DateDiff[i])).

data <- tibble(Date = c(20190309, 20190507, 20190707, 20190907, 20191018, 20191210, 20200120),
             Incoming = c(0, 35, 27, 108, 5, 12, 30),
             Inventory = c(40, 0, 0, 0, 0, 0, 0))

Это tibble требует небольшой работы:

data <- data %>%
  mutate(Date = as.Date(as.character(Date), "%Y%m%d")) %>%
  mutate(DateDiff = Date - lag(Date, 1))  %>%# calculate time difference with previous row
  mutate(DateDiff = replace_na(DateDiff, 0))

И поскольку мне нужно обрабатывать первую строку иначе, чем другие строки, мне нужно использовать for-l oop:

for (i in seq_len(nrow(data))) {
  if (i == 1) {
    data$Inventory [i] <- data$Inventory [i] + data$Incoming[i]
  } else {
    data$Inventory [i] <- data$Inventory [i - 1] + data$Incoming[i] - as.numeric(data$DateDiff[i])
  }
}

С этим выводом:

> data
# A tibble: 7 x 4
  Date       Incoming Inventory DateDiff
  <date>        <dbl>     <dbl> <drtn>  
1 2019-03-09        0        40  0 days 
2 2019-05-07       35        16 59 days 
3 2019-07-07       27       -18 61 days 
4 2019-09-07      108        28 62 days 
5 2019-10-18        5        -8 41 days 
6 2019-12-10       12       -49 53 days 
7 2020-01-20       30       -60 41 days 

Это можно легко расширить, чтобы включить группы. Это полезно?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...