首页 文章

groupby总结在groupby dplyr之外

提问于
浏览
2

我正在尝试使用此数据集中的日期对ID进行分组,但我想基于该组之外的某个功能进行汇总 .

library(dplyr)
library(lubridate)

set.seed(100)
df <- data.frame(ids = sample(c('436247', '2465347', '346654645'), 10000, replace=TRUE),
                 date = sample(seq.Date(ymd('2018-03-01'), ymd('2018-05-01'), by=1), 10000, replace=TRUE))

new_df <- df %>%
    group_by(ids, date) %>%
    summarise(events = length(ids[date >= date - 30 & date <= date]))

我正在尝试使用此数据框并回答问题 - "for each of the ids, and each date, how many other records within that id, are within the past 30 days of that date" . 不幸的是,当我 group_by ids和日期时,它只在分组日期内查看 . 我在下面创建了解决方案,但不确定dplyr是否有更好的解决方案?

groupby_function <- function(df, spec_date){
  result <- df %>%
      group_by(ids) %>%
      summarise(events = length(ids[date >= spec_date - 30 & date <= spec_date])) %>%
      mutate(date = spec_date)
  return(result)

} 

date_vector <- seq.Date(ymd('2018-03-01'), ymd('2018-05-01'), by=1)
list_results <- lapply(date_vector, groupby_function, df=df)
x <- do.call(rbind, list_results)

4 回答

  • 1

    “对于每个ID,每个日期,该ID中有多少其他记录,在该日期的过去30天内”

    为此,"join by"条件是有道理的,但isn't yet included in dplyr . 在此之前,您可以在dplyr链中使用data.table:

    # enumerate id-date combos of interest
    grid_df = expand.grid(
      id = unique(df$ids), 
      d = seq(min(df$date), max(df$date), by="day")
    )
    
    # helper function
    library(data.table)
    count_matches = function(DF, targetDF, ...){
      onexpr = substitute(list(...))
      data.table(targetDF)[DF, on=eval(onexpr), .N, by=.EACHI]$N
    }
    
    # use a non-equi join to count matching rows
    res = grid_df %>% 
      mutate(d_dn = d - 30) %>% 
      mutate(n = count_matches(., df, ids = id, date >= d_dn, date <= d)) %>% 
      as.tibble
    
    # A tibble: 186 x 4
              id          d       d_dn     n
          <fctr>     <date>     <date> <int>
     1    436247 2018-03-01 2018-01-30    72
     2   2465347 2018-03-01 2018-01-30    69
     3 346654645 2018-03-01 2018-01-30    51
     4    436247 2018-03-02 2018-01-31   123
     5   2465347 2018-03-02 2018-01-31   120
     6 346654645 2018-03-02 2018-01-31   100
     7    436247 2018-03-03 2018-02-01   170
     8   2465347 2018-03-03 2018-02-01   166
     9 346654645 2018-03-03 2018-02-01   154
    10    436247 2018-03-04 2018-02-02   228
    # ... with 176 more rows
    

    我认为它应该适用于平等条件写 ids = idids == id .

    如果您有兴趣,语法是 x[i, on=, j, by=.EACHI] ,其中 xi 是表格 . 对于 i 的每一行,我们根据 on= 条件查找 x 的行(左侧是指 x 中的列;右侧是 i 中的列);那么我们每个都做 j (“每行 i ”所以 by=.EACHI ) . 在这种情况下, j = .N 表示我们计算匹配的 x 行,作为计数列 N 返回 .

  • 0

    您只需返回原始数据框(调用 df$datedf$ids )即可查看"ungrouped"数据 . 所以我认为你所追求的是

    test_df <- df %>%
      group_by(ids, date) %>%
      summarise(events = length(df$ids[df$date >= date[1] - 30 & df$date <= date[1] & df$ids == ids[1]]))
    

    另外,我运行了你提出的函数,但我没有看到原始 group_by 解决方案的结果有任何差异,所以我认为这不是你想要的 .

  • 0

    如果“非dplyr”解决方案是可以接受的,那么这可以为您提供所需的解决方案 .

    df$diff <- as.vector(
      sapply(unique(df$ids), function(x)
        sapply(df$date[df$ids == x], function(y)
          sum(abs(y - df$date[df$ids == x]) >= 30)
          )
        )
      )
    

    或者,在 dplyr 中,您可以使用以下方式获得如上所示的结果:

    f <- function(x) {
      sapply(x, function(y) sum(abs(y - x) >= 30))
      }
    
    df$diff <- unlist(
      df %>%
        group_by(ids) %>%
        do(diff = f(.$date)) %>%
        .$diff
      )
    
  • 0

    这里's an answer. But it assumes there'是每个 id 的连续日期序列 .

    df %>%
      group_by(ids, date) %>%
      count() %>%
      arrange(ids, date) %>%
      group_by(ids) %>%
      mutate(
        events = cumsum(n) - cumsum(lag(n, 30, 0))
      )
    

相关问题