dplyr mutate调用另一个数据帧

时间:2016-09-25 16:31:44

标签: r dplyr

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

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

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 个答案:

答案 0 :(得分: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来自purrr

的其他选项为dplyr
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

答案 1 :(得分: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来计算id中每个df1条件为真的出现次数。然后,按id分组并将其用于summarise

如果每start_timeid可能更多,那么您可以使用相同的功能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