从两列中查找滚动最小和最大出现次数

Find rolling min and max occurrences from two columns

我想跟踪两列中的最小和最大出现次数。这应该从数据开始以滚动方式完成,因此我们可以跟踪每个日期总体 ID 出现的次数。同样,ID 出现在哪个列中也无关紧要。

结果应该如下。第 1 行,B 或 C 均未发生,因此 min_appearance 为 0 但 max_appearance 为 1,因为存在 A 和 D。第 5 行 A 和 D 在这一点上出现了 3 次,但 B 和 C 只有 2 次。我不关心哪个 ID 存在,但只关心最小值和最大值。而且真实数据更复杂,所以对不是静态的,但是A可以面对C等等。

# A tibble: 8 x 5
  date       id1   id2   min_appearances max_appearances
  <date>     <chr> <chr>           <dbl>           <dbl>
1 2020-01-01 A     D                   0               1
2 2020-01-02 B     C                   1               1
3 2020-01-03 C     B                   1               2
4 2020-01-04 D     A                   2               2
5 2020-01-05 A     D                   2               3
6 2020-01-06 B     C                   3               3
7 2020-01-07 C     B                   3               4
8 2020-01-08 D     A                   4               4

数据:

library(dplyr)

date <-  seq(as.Date("2020/1/1"), by = "day", length.out = 8)
id1 <- rep(c("A", "B", "C", "D"), 2)
id2 <- rep(c("D", "C", "B", "A"), 2)

dt <- tibble(date = date,
             id1 = id1,
             id2 = id2)

这是一种使用 tidyverse 中的函数来实现的方法。首先,pivot_longer 处理数据更容易。然后计算每个唯一值 ids 的累积值计数。计算“计数”列中每一行的最小值和最大值。最后,取每对的最后一个最小值和最大值,然后转向宽。

library(tidyverse)

dt %>% 
  pivot_longer(cols = -date, values_to = "id") %>% 
  mutate(map_dfc(unique(id), ~ tibble("count_{.x}" := cumsum(id == .x)))) %>% 
  mutate(min_appearances = do.call(pmin, select(., starts_with("count"))),
         max_appearances = do.call(pmax, select(., starts_with("count")))) %>% 
  group_by(date) %>% 
  mutate(across(min_appearances:max_appearances, last),
         n = row_number()) %>% 
  pivot_wider(c(date, min_appearances, max_appearances), names_from = n, values_from = id, names_prefix = "id") %>% 
  relocate(order(colnames(.)))

  date       id1   id2   max_appearances min_appearances
  <date>     <chr> <chr>           <int>           <int>
1 2020-01-01 A     D                   1               0
2 2020-01-02 B     C                   1               1
3 2020-01-03 C     B                   2               1
4 2020-01-04 D     A                   2               2
5 2020-01-05 A     D                   3               2
6 2020-01-06 B     C                   3               3
7 2020-01-07 C     B                   4               3
8 2020-01-08 D     A                   4               4