首页 文章

dplyr mutate调用另一个数据帧

提问于
浏览
5

我想通过应用一个调用另一个数据帧的函数来改变数据帧 . 我可以通过几种不同的方式实现这一点,但我想知道如何“正确”地做到这一点 .

这是我正在尝试做的一个例子 . 我有一个数据帧有一些开始时间,第二个有一些定时观察 . 我想返回一个数据帧,其中包含开始时间,以及在开始时间之后某些窗口中发生的观察数 . 例如

set.seed(1337)
df1 <- data.frame(id=LETTERS[1:3], start_time=1:3*10)
df2 <- data.frame(time=runif(100)*100)
lapply(df1$start_time, function(s) sum(df2$time>s & df2$time<(s+15)))

到目前为止我用dplyr得到的最好的是以下内容(但这会失去身份变量):

df1 %>% 
    rowwise() %>%
    do(count = filter(df2, time>.$start_time, time < (.$start_time + 15))) %>%
    mutate(n=nrow(count))

输出:

Source: local data frame [3 x 2]
Groups: <by row>

# A tibble: 3 × 2
                  count     n
                 <list> <int>
1 <data.frame [17 × 1]>    17
2 <data.frame [18 × 1]>    18
3 <data.frame [10 × 1]>    10

我原以为能够做到这一点:

df1 <- data.frame(id=LETTERS[1:3], start_time=1:3*10)
df2 <- data.frame(time=runif(100)*100)
df1 %>% 
    group_by(id) %>% 
    mutate(count = nrow(filter(df2, time>start_time, time<(start_time+15))))

但是这会返回错误:

Error: comparison (6) is possible only for atomic and list types

dplyr的做法是什么?

2 回答

  • 3

    这是一个选项 data.table ,我们可以使用 non-equi 连接

    library(data.table)#1.9.7+
    setDT(df1)[, start_timeNew := start_time + 15]
    setDT(df2)[df1, .(id, .N), on = .(time > start_time, time < start_timeNew), 
               by = .EACHI][, c('id', 'N'), with = FALSE]
    #   id  N
    #1:  A 17
    #2:  B 18
    #3:  C 10
    

    它给出了与OP的 base R 方法相同的计数

    sapply(df1$start_time, function(s) sum(df2$time>s & df2$time<(s+15)))
    #[1] 17 18 10
    

    如果我们还需要'id'变量作为 dplyr 中的输出,我们可以修改OP的代码

    df1 %>%
        rowwise() %>% 
        do(data.frame(., count = filter(df2, time>.$start_time,
                                     time < (.$start_time + 15)))) %>% 
        group_by(id) %>% 
        summarise(n = n())
    #      id     n
    #  <fctr> <int>
    #1      A    17
    #2      B    18
    #3      C    10
    

    或者另一个选项 map 来自 purrrdplyr

    library(purrr)
    df1 %>% 
        split(.$id) %>% 
        map_df(~mutate(., N = sum(df2$time >start_time & df2$time < start_time + 15))) %>% 
        select(-start_time)
    #   id  N
    #1  A 17
    #2  B 18
    #3  C 10
    
  • 2

    使用 dplyr 的另一种略有不同的方法:

    result <- df1 %>% group_by(id) %>% 
                      summarise(count = length(which(df2$time > start_time &
                                                     df2$time < (start_time+15))))
    
    print(result)
    ### A tibble: 3 x 2
    ##      id count
    ##  <fctr> <int>
    ##1      A    17
    ##2      B    18
    ##3      C    10
    

    我相信您可以使用 lengthwhich 来计算 df1 中每个 id 条件为真的出现次数 . 然后,按 id 分组并将其用于 summarise .


    如果每个 id 可能还有一个 start_time ,那么你可以使用相同的函数,但 rowwisemutate

    result <- df1 %>% rowwise() %>% 
                      mutate(count = length(which(df2$time > start_time & 
                                                  df2$time < (start_time+15))))
    print(result)
    ##Source: local data frame [3 x 3]
    ##Groups: <by row>
    ##
    ### A tibble: 3 x 3
    ##      id start_time count
    ##  <fctr>      <dbl> <int>
    ##1      A         10    17
    ##2      B         20    18
    ##3      C         30    10
    

相关问题