【问题标题】:time series group by and filter in dplyr rdplyr r 中的时间序列分组和过滤
【发布时间】:2017-12-18 21:49:26
【问题描述】:

我正在尝试在数据框中查找组中的特定模式。获取以下通过电子邮件下订单的数据框、下订单的人以及金额。

set.seed(123)
dates = sample(seq(as.Date("2017-01-01"),as.Date("2017-12-31"), by = 'day'), 2000, replace = TRUE)
amount <- sample(-50:100, 2000, replace = TRUE)
placedorder <- sample(c(NA, NA, NA, "jeff", "alex", "steve", "amy", "john", "larry", "ryan"), 2000, replace = TRUE)
email <- sample(paste0(1:200, "@gmail.com"), 2000, replace = TRUE)
df <- data.frame(dates, email, placedorder, amount, stringsAsFactors = FALSE)

我想按电子邮件地址查找所有这三个发生位置的组,它们在日期连续出现的位置:

  1. 下达了一个值且placedorder为NA
  2. 的订单
  3. 在上述步骤后下单,值且placedorder为NA
  4. 在第 2 步之后下订单,其值为 ,其中placeholder不适用

示例:

# A tibble: 10 x 4
# Groups:   email [1]
        dates       email placedorder amount
       <date>       <chr>       <chr>  <int>
 1 2017-02-10 1@gmail.com        <NA>     68 # satisfies #1
 2 2017-02-27 1@gmail.com        <NA>    -21 # satisfies #2
 3 2017-03-07 1@gmail.com        jeff     -9
 4 2017-03-09 1@gmail.com       steve    -93
 5 2017-03-14 1@gmail.com       steve     22 # satisfies #3
 6 2017-03-18 1@gmail.com       steve    -81
 7 2017-04-28 1@gmail.com        <NA>    -12
 8 2017-05-06 1@gmail.com        <NA>      4
 9 2017-06-03 1@gmail.com        jeff    -40
10 2017-06-03 1@gmail.com       larry     13 #(this also satisfies #3)

上面的例子都在同一个email内,3个过滤器中的每一个在时间上一个接一个地发生。

我的尝试,我认为找到了这些发生的位置,但没有考虑日期和连续发生的情况。此外,最好将其过滤到仅这些订单。

df2 <- df %>%
  group_by(email) %>%
  filter(any(is.na(placedorder) & amount > 0),
         any(is.na(placedorder) & amount < 0),
         any(!is.na(placedorder) & amount > 0)
  )

提前致谢!

【问题讨论】:

  • 几个问题。当您说“之后”或仅根据数据集行号时,您是在谈论时间连续性?如果是临时的,请先对日期和电子邮件的数据集进行排序(对电子邮件进行排序以节省计算时间)。其次,您是否要过滤以同时满足所有三个条件?此外,如果您的问题是由于您的日期为 POSIXct 引起的,您可能希望根据需要将其转换为字符并再次转换回来,这很麻烦,但以后更容易调试(如果有注释)。
  • 我的意思是“之后”,因为它发生在第一次出现之后的日期。我确实想过滤,以便在给定组内同时满足所有三个条件,并发生在一个接一个发生的日期(可以是日期之间的任何距离,只是必须在之后)
  • 编辑帖子以显示示例

标签: r filter group-by dplyr


【解决方案1】:

假设我对“一阶”和“二阶”的解释是正确的,下面是设置dplyr 中命令的一种方法

library(dplyr)

df %>% group_by(email) %>% 
  arrange(email, dates) %>% 
  mutate(order_num=1:n()) %>% 
  #An order was placed with a positive value and where placedorder is NA
  filter((is.na(placedorder) & amount>0) |
  # An order was placed after the first one, with a negative value and where placedorder is NA
         (is.na(placedorder) & amount <0 & order_num >1) |
  # An order was placed after the second order, with a positive value and where placeholder is not NA
        (!is.na(placedorder) & amount >0 & order_num > 2)
    )

更新: 非常感谢您澄清问题。基本上,您希望“观察客户状态”并仅在观察到前一个类型之后才开始跟踪下一个类型的事件。这是一个(有点冗长,但希望可以理解)尝试跟踪客户在这些“状态”中转换的尝试:

df %>% group_by(email) %>% 
  arrange(email, dates) %>% 
  mutate(event_1=ifelse(is.na(placedorder) & amount>0, 1, 0),
         post_event_1=cumsum(event_1),
         # only if at least one event_1 has happened
         event_2=ifelse(post_event_1>=1 & is.na(placedorder) & amount <0, 1,0),
         post_event_2=cumsum(event_2),
         # only if at least one event_2 has happened
         event_3=ifelse(post_event_2>=1 & !is.na(placedorder) & amount >0, 1, 0)) %>% 
  # only interested in first occurance of event_1 and event_2 preceding event_3
  filter((event_1==1 & post_event_1==1) | (event_2==1 & post_event_2==1) | event_3 ==1)

# A tibble: 390 x 9
# Groups:   email [165]
        dates         email placedorder amount event_1 post_event_1 event_2 post_event_2 event_3
       <date>         <chr>       <chr>  <int>   <dbl>        <dbl>   <dbl>        <dbl>   <dbl>
 1 2017-01-29   1@gmail.com        <NA>     76       1            1       0            0       0
 2 2017-05-25   1@gmail.com        <NA>    -37       0            1       1            1       0
 3 2017-08-14   1@gmail.com       steve     53       0            1       0            2       1
 4 2017-12-21   1@gmail.com        john     92       0            2       0            4       1
 5 2017-02-08 100@gmail.com        <NA>     89       1            1       0            0       0
 6 2017-01-16 101@gmail.com        <NA>     40       1            1       0            0       0
 7 2017-03-18 102@gmail.com        <NA>     20       1            1       0            0       0
 8 2017-05-16 102@gmail.com        <NA>    -45       0            2       1            1       0
 9 2017-06-08 102@gmail.com       larry     46       0            2       0            2       1
10 2017-07-22 102@gmail.com        john     93       0            3       0            2       1
# ... with 380 more rows

有一些“未完成的链”,例如当客户进展到 state_1 但没有进一步时。不确定是否要删除那些(因为您可以计算每封电子邮件的观察结果并删除那些少于 3 条记录的)。

【讨论】:

  • 感谢@dmi3kno。所以首先 - 我需要通过电子邮件进行分组。它必须发生在同一封电子邮件中。但最重要的是,我认为我没有澄清“一阶”和“二阶”。在 11 月的第 1 天到第 20 天可能会有 20 个订单。我想找到在任何给定日期发生 1 次,然后是 2 次,然后是 3 次的实例,但是这些日期必须一个接一个。
  • 我想 OP 想要 & 而不是 |,从他的评论来看。顺便说一句,答案很好。
  • 是的,我确实想要,但是 order_num 也不起作用。我在帖子中添加了更多说明,提供了更多细节!
  • 按日期排序,然后添加订单号的辅助列可以满足您的需要,基本上。
  • @MattW。在运行其余代码之前,添加一个带有df$ORDER_NUM &lt;- seq(1:nrow(df)) 的帮助器列。然后,您将不需要 mutate 部分。
猜你喜欢
  • 1970-01-01
  • 2020-05-24
  • 1970-01-01
  • 2022-01-16
  • 1970-01-01
  • 1970-01-01
  • 2018-06-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多