在大型数据帧上使用 rle()

using rle() on a large dataframe

我正在尝试查找一个 ID 具有任何分数的连续 运行 的数量,按日期排序。 我遇到了一个使用 apply() 的简单方法,它似乎有效,但是,它只给出了每个 运行 的长度,而不是与之相关的分数或 ID。

数据框由以下内容组成:

DATE         ID     SCORE
2021-04-05   12690   67
2021-04-05   12278   47
2021-04-05   12153   64
---
2021-03-26   12690   88
2021-03-26   12278   47
---
2021-03-20   12690   67
+ 120,000 more rows

日期格式为 YYYY-MM-DD

基于上面的示例 df,我希望它 return 类似于以下内容:

12690   67    1
12690   88    1
12690   67    1
12278   47    2
12153   64    1

即对于 ID 12690,分数 67 出现一次,然后 88 一次,然后 67 一次,依此类推

如果我强制它一次只使用一个 ID,我可以让它工作,但这似乎不是很有效。最好的方法是什么? TIA

这是对提供的数据起作用的尝试。如果它不适用于您的真实数据,post 稍微复杂一点的示例数据集,我们可以再试一次。

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
dat <- tibble::tribble(
  ~DATE,         ~ID,     ~SCORE,
"2021-04-05", 12690,   67,
"2021-04-05",   12278,   47,
"2021-04-05", 12153,   64,
"2021-03-26",   12690,   88,
"2021-03-26", 12278,   47,
"2021-03-20",   12690,   67) %>% 
  mutate(DATE = lubridate::ymd(DATE))


tmp <- dat %>% 
  arrange(ID, DATE) %>% 
  group_by(ID) %>% 
  mutate(eq = SCORE == lead(SCORE), 
         eq = case_when(is.na(eq) ~ FALSE, 
                     TRUE ~ eq), 
         eq = case_when(!eq ~ SCORE == lag(SCORE), 
                        TRUE ~ eq), 
         eq = case_when(is.na(eq) ~ FALSE, 
                        TRUE ~ eq)) 

tmps <- tmp %>% split(tmp$eq)
tmps[[2]] <- tmps[[2]] %>% 
  group_by(ID, SCORE) %>% 
  summarise(n = sum(eq))
#> `summarise()` has grouped output by 'ID'. You can override using the `.groups`
#> argument.
tmps[[1]] <- tmps[[1]] %>%
  select(ID, SCORE) %>% 
  mutate(n=1)

bind_rows(tmps)
#> # A tibble: 5 × 3
#> # Groups:   ID [3]
#>      ID SCORE     n
#>   <dbl> <dbl> <dbl>
#> 1 12153    64     1
#> 2 12690    67     1
#> 3 12690    88     1
#> 4 12690    67     1
#> 5 12278    47     2

reprex package (v2.0.1)

创建于 2022-04-13

这里有一个替代方案,可以将相同 ID 的相同号码的不同运行分开。

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
dat <- tibble::tribble(
  ~DATE,         ~ID,     ~SCORE,
  "2021-04-05", 12690,   67,
  "2021-04-05",   12278,   47,
  "2021-04-05", 12153,   64,
  "2021-03-26",   12690,   88,
  "2021-03-26", 12278,   47,
  "2021-03-20",   12690,   67) %>% 
  mutate(DATE = lubridate::ymd(DATE))

tmp <- dat %>% 
  arrange(ID, DATE) %>% 
  group_by(ID) %>% 
  mutate(obs = 1:n()) %>% 
  ungroup %>% 
  mutate(new_grp = as.numeric(SCORE != lag(SCORE) | ID != lag(ID) | obs != lag(obs) + 1), 
         new_grp = ifelse(is.na(new_grp), 1, new_grp), 
         group = cumsum(new_grp)) %>% 
  group_by(ID, SCORE, group) %>% 
  summarise(n = n()) %>% 
  ungroup %>% 
  select(-group)
#> `summarise()` has grouped output by 'ID', 'SCORE'. You can override using the
#> `.groups` argument.

tmp
#> # A tibble: 5 × 3
#>      ID SCORE     n
#>   <dbl> <dbl> <int>
#> 1 12153    64     1
#> 2 12278    47     2
#> 3 12690    67     1
#> 4 12690    67     1
#> 5 12690    88     1

reprex package (v2.0.1)

于 2022-04-14 创建