【问题标题】:R new variable by group looped on multiple lagged and lead valuesR按组的新变量在多个滞后和领先值上循环
【发布时间】:2019-12-09 00:35:06
【问题描述】:

假设我有三个变量iddatetrad(它有 3 个值,并且在任何时间点都可以是其中的任何一个):

library(tidyverse) 
dput(df)
    structure(list(id = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
    1, 1, 1, 2, 2, 2), date = structure(c(16436, 16437, 16438, 16439, 
    16440, 16441, 16442, 16443, 16444, 16445, 16446, 16447, 16448, 
    16449, 16450, 16451, 16452, 16453, 16454), class = "Date"), trad = c("Free", 
    "Suspended", "Suspended", "Free", "Suspended", "Withdrawn", "Withdrawn", 
    "Free", "Withdrawn", "Free", "Free", "Withdrawn", "Suspended", 
    "Withdrawn", "Withdrawn", "Free", "Withdrawn", "Suspended", "Free"
    )), class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame"), row.names = c(NA, 
    -19L), spec = structure(list(cols = list(id = structure(list(), class = c("collector_double", 
    "collector")), date = structure(list(format = "%d/%m/%Y"), class = c("collector_date", 
    "collector")), trad = structure(list(), class = c("collector_character", 
    "collector"))), default = structure(list(), class = c("collector_guess", 
    "collector")), skip = 1), class = "col_spec"))
    df
    # A tibble: 19 x 3
          id date       trad     
       <dbl> <date>     <chr>    
     1     1 2015-01-01 Free     
     2     1 2015-01-02 Suspended
     3     1 2015-01-03 Suspended
     4     1 2015-01-04 Free     
     5     1 2015-01-05 Suspended
     6     1 2015-01-06 Withdrawn
     7     1 2015-01-07 Withdrawn
     8     1 2015-01-08 Free     
     9     1 2015-01-09 Withdrawn
    10     1 2015-01-10 Free     
    11     1 2015-01-11 Free     
    12     1 2015-01-12 Withdrawn
    13     1 2015-01-13 Suspended
    14     1 2015-01-14 Withdrawn
    15     1 2015-01-15 Withdrawn
    16     1 2015-01-16 Free     
    17     2 2015-01-17 Withdrawn
    18     2 2015-01-18 Suspended
    19     2 2015-01-19 Free 

我想生成新列,其中包含一个时期的开始日期和结束日期。当trad 移动到状态"Withdrawn" 时开始一段时期,但需要注意的是,如果在"Withdrawn" 行之前存在状态"Suspended",则开始日期将移至该行。如果"Withdrawn" 之前有多行"Suspended",则从第一个"Suspended" 开始。同样,结束日期是trad 在进入"Withdrawn" 之后转到Free 的时间。这是必需的最终数据集:

dfnew
# A tibble: 19 x 6
      id date       trad      start      end        period
   <dbl> <date>     <chr>     <date>     <date>      <dbl>
 1     1 2015-01-01 Free      NA         NA             NA
 2     1 2015-01-02 Suspended NA         NA             NA
 3     1 2015-01-03 Suspended NA         NA             NA
 4     1 2015-01-04 Free      NA         NA             NA
 5     1 2015-01-05 Suspended 2015-01-05 NA              1
 6     1 2015-01-06 Withdrawn NA         NA              1
 7     1 2015-01-07 Withdrawn NA         NA              1
 8     1 2015-01-08 Free      NA         2015-01-08      1
 9     1 2015-01-09 Withdrawn 2015-01-09 NA              2
10     1 2015-01-10 Free      NA         2015-01-10      2
11     1 2015-01-11 Free      NA         NA             NA
12     1 2015-01-12 Withdrawn 2015-01-12 NA              3
13     1 2015-01-13 Suspended NA         NA              3
14     1 2015-01-14 Withdrawn NA         NA              3
15     1 2015-01-15 Withdrawn NA         NA              3
16     1 2015-01-16 Free      NA         2015-01-16     NA
17     2 2015-01-17 Withdrawn 2015-01-17 NA              1
18     2 2015-01-18 Suspended NA         NA              1
19     2 2015-01-19 Free      NA         2015-01-19      1 

trad 中没有模式,所以你可以在"Free" 之前有任何"Withdrawn"/"Suspended" 序列,所以这样的解决方案不起作用(理论上它可以,但我也需要实现它的许多条件):

dfnew <- df %>% 
  group_by(id)
  mutate(start = ifelse(trad == "Withdrawn" & lag(trad == "Free"), date, NA))

这些问题很有帮助,但不回答问题:

How to extract the previous n rows where a certain column value cannot be a particular value?

R - Conditional lagging - How to lag a certain amount of cells until a condition is met?

有人有灵活的解决方案吗?

【问题讨论】:

    标签: r loops dataframe dplyr tidyverse


    【解决方案1】:

    不是很灵活,但至少可以尝试一下。

    我不知道当我们有序列 Suspended、Suspended、Withdrawn、Withdrawn 时会发生什么。

    例如,将 2015 年 1 月 4 日的传统更改为暂停。在这种情况下,开始日期是什么时候? 我给出了 2 个解决方案,第一个在 2015-01-02 开始日期,第二个在 2015-01-05

    dfnew1 <- df %>% 
        mutate(startGroups = cumsum(trad == "Free")) %>% 
        group_by(startGroups) %>% # make a group from every occurance of "Free" in trad
        mutate(wds = cumsum(trad == "Withdrawn"),
               start = ifelse(max(wds) > 0 & row_number() == 2, date, NA) # if there is any "Withdrawn" in the group set start date right after "Free" 
               ) %>% 
        ungroup() %>% 
        mutate(endGroups = cumsum(!is.na(start))) %>% 
        group_by(endGroups) %>% # group on every open trade now
        mutate(frees = cumsum(trad == "Free"),
               end = ifelse(frees == 1 & endGroups > 0, date, NA) #end on first occurance of "Free" in trad column
               ) # %>% select(-startGroups, wds, endGroups, frees) # remove cols
    
    dfnew2 <- df %>% 
        mutate(startGroups = cumsum(trad == "Free")) %>% 
        group_by(startGroups) %>% # make a group from every occurance of "Free" in trad
        mutate(wds = cumsum(trad == "Withdrawn"),
               start = ifelse(
                            (trad == "Suspended" & lead(trad) == "Withdrawn" & lead(wds) == 1 |
                                trad == "Withdrawn" & lag(trad) != "Suspended" & wds == 1), 
                           date, NA) # first trad in group. Other option: 
        ) %>% 
        ungroup() %>% 
        mutate(endGroups = cumsum(!is.na(start))) %>% 
        group_by(endGroups) %>% 
        mutate(frees = cumsum(trad == "Free"),
               end = ifelse(frees == 1 & endGroups > 0, date, NA)
        )  #%>% select(-startGroups, wds, endGroups, frees)
    

    【讨论】:

    • 有趣的工作,谢谢。它可能会奏效,我会在回到办公桌前尝试一下。如果 Suspended 在 2015-01-04 上,那么开始时间是 2015-01-02。一旦Withdrawn,开始总是在最后一个Free之前的最后一个Suspended的日期(或者如果没有Suspended,则只是Withdrawn的日期,如2015-01-12的情况)
    猜你喜欢
    • 2022-01-25
    • 1970-01-01
    • 2018-09-01
    • 1970-01-01
    • 2019-09-05
    • 1970-01-01
    • 1970-01-01
    • 2018-07-01
    • 1970-01-01
    相关资源
    最近更新 更多