dplyr :: mutate在另一个数据框的不同列上有多个条件

时间:2015-11-06 20:34:56

标签: r dplyr

修改 我留下这个问题,以防它对某人有帮助,但它似乎实际上是dplyr版本的问题[见下文]。

R并使用dplyr,我有两个数据框df1df2

library(dplyr)
set.seed(2)
df1 = data.frame(letter=rep(letters[1:2], each=5), min=runif(10))
df1 = mutate(df1, max=min+runif(10))
df2 = data.frame(letters=rep(letters[1:2], 25), position=runif(50), val=rnorm(50))

对于df1的每一行,我想计算所有df2$val的总和,df2$position介于df1$mindf1$max之间df2$letters }等于df1$letter

this question on SO开始,我可以完成条件的第一部分(即df2$positiondf1$min之间的df1$max):

incompleteCond = df1 %>% rowwise %>% 
  mutate(sumval = sum( df2$val[between(df2$position, min, max)] ))

但这是对满足此条件的df2行的求和,而不确保df2$letters与相应的df1$letter一致。如何在其他列中添加此条件? 以下尝试不起作用:

# Note: these solutions actually DO the job with dplyr_0.4.3!
wrong1 = df1 %>% rowwise %>% 
  mutate(sumval = 
           sum( df2$val[between(df2$position, min, max) & df2$letters==letter] ))

wrong3 = df1 %>% rowwise %>% 
  mutate(sumval = 
           sum( df2[(df2$position>=min) & (df2$position<=max) & (df2$letters==letter),
                    'val'] ))

修改

看起来这实际上是版本问题:从dplyr_0.4.1转到dplyr_0.4.3解决了问题,这意味着上面的wrong1wrong3实际上都是正确的(他们只给出版本为0.4.1的零...)

作为旁注,我还没有找到dplyr - 只有子集(filterdf2的解决方案,但上面的工作方式,以及不错的回答@ r2evans。

1 个答案:

答案 0 :(得分:1)

我认为你很接近:

df1 %>%
    rowwise() %>%
    mutate(sumval = sum( df2$val[df2$letters == letter & between(df2$position, min, max)] ))
## Source: local data frame [10 x 4]
## Groups: <by row>
##    letter       min       max     sumval
##    (fctr)     (dbl)     (dbl)      (dbl)
## 1       a 0.1848823 0.7375563 -3.8432366
## 2       a 0.7023740 0.9412688 -0.9138266
## 3       a 0.5733263 1.3338396  4.1341039
## 4       a 0.1680519 0.3488720 -2.5142686
## 5       a 0.9438393 1.3491215  3.6405305
## 6       b 0.9434750 1.7970234 -0.1416608
## 7       b 0.1291590 1.1055575 -5.2083130
## 8       b 0.8334488 1.0592743  1.0618699
## 9       b 0.4680185 0.9128277 -2.3595283
## 10      b 0.5499837 0.6249632  0.0000000

@aosmith建议的另一个选择是首先加入两个数据集。

df1 %>%
    mutate(grp = 1:n()) %>%
    left_join(df2, by=c('letter'='letters')) %>%
    filter(position >= min & position <= max) %>%
    group_by(grp) %>%
    summarize(letter=letter[1], min=min[1], max=max[1], sumval=sum(val)) %>%
    select(-grp)
## Source: local data frame [9 x 4]
##   letter       min       max     sumval
##   (fctr)     (dbl)     (dbl)      (dbl)
## 1      a 0.1848823 0.7375563 -3.8432366
## 2      a 0.7023740 0.9412688 -0.9138266
## 3      a 0.5733263 1.3338396  4.1341039
## 4      a 0.1680519 0.3488720 -2.5142686
## 5      a 0.9438393 1.3491215  3.6405305
## 6      b 0.9434750 1.7970234 -0.1416608
## 7      b 0.1291590 1.1055575 -5.2083130
## 8      b 0.8334488 1.0592743  1.0618699
## 9      b 0.4680185 0.9128277 -2.3595283

您可能会注意到的一个区别是,最后一个“b”组未包含在后一组中,因为没有数据在给定范围内。

编辑:我将连接代码从使用between(不会将最小/最大参数向量化)更改为更简单的向量比较,从而否定了使用{{的性能惩罚1}}。我还删除了rowwise,因为在ungroup之后,无论如何都会删除分组。

供参考:

summarize