dplyr-用条件总结

我有这个数据框:

library(dplyr)
library(tidyr)

data <- tribble(
  ~Date, ~A1, ~A2,~B1,~B2,
  as.Date("2019-01-01"), 20, 10,20, 10,
  as.Date("2019-01-01"), 20 ,5,20,5,
  as.Date("2019-01-01"), 10, 2,10,20,
  as.Date("2019-01-01"), 20, 60,0,0,
  as.Date("2019-01-01"), 30, 4,20,5,
  as.Date("2019-02-01"), 0, 0,16,8,
  as.Date("2019-02-01"), 0, 0,0,40,
  as.Date("2019-02-01"), 0, 0,4,2,
  as.Date("2019-02-01"), 4, 8,10,6,
  as.Date("2019-02-01"), 6, 3,0,0,
  as.Date("2019-03-01"), 20, 8,23,9,
  as.Date("2019-03-01"), 60, 4,0,0,
  as.Date("2019-03-01"), 4, 2,8,3,
  as.Date("2019-03-01"), 0, 6,10,0
)

对于每一天,我想计算 (A1-B1) 和 (A2-B2) 的平均值。
对于 A1-B1,我只想使用 A1>B1 和 A1>0,B1>0 的行。
对于 A2-B2,我只想使用 A2>B2 和 A2>0,B2>0 的行。

这是我尝试过的:

data_mean = data %>%
    group_by(Date) %>%
    dplyr::summarise(
      mean_1 = mean(A1[A1>=B1 & A1>0 & B1>0] - B1[A1>=B1 & A1>0 & B1>0]),
      mean_2 = mean(A2[A2>=B2 & A2>0 & B2>0] - B2[A2>=B2 & A2>0 & B2>0]))

有没有办法在使用汇总功能的同时使用过滤功能?或者更聪明的方式来应用我的代码?

回答

如果我们不想重复这些表达式,请创建一个临时列。此外,这可以在多个列中完成across

library(dplyr)
library(stringr)
data %>% 
   group_by(Date) %>% 
   summarise(across(c(A1, A2), ~ {
       tmp <- get(str_replace(cur_column(), 'A', 'B'))
       i1 <- . >= tmp & . > 0 & tmp >0
       mean(.[i1] - tmp[i1])})) %>%
   rename_with(~ str_replace(., 'A', 'mean_'), -Date)

-输出

# A tibble: 3 x 3
#  Date       mean_1 mean_2
#* <date>      <dbl>  <dbl>
#1 2019-01-01    2.5      0
#2 2019-02-01  NaN        2
#3 2019-03-01  NaN      NaN

或者另一种选择是使用 转换为“长”格式pivot_longerfilter/group_by/summarise然后使用pivot_wider

library(tidyr)
data %>% 
   pivot_longer(cols = A1:B2, names_to = c('.value', 'grp'), 
       names_sep = '(?<=[A-Z])(?=d)') %>% 
   filter(A >= B, A > 0, B > 0) %>% 
   group_by(Date, grp = str_c('mean_', grp)) %>%
   summarise(mean = mean(A - B), .groups = 'drop') %>% 
   pivot_wider(names_from = grp, values_from = mean) %>%
   complete(Date = unique(data$Date))
# A tibble: 3 x 3
#  Date       mean_1 mean_2
#  <date>      <dbl>  <dbl>
#1 2019-01-01    2.5      0
#2 2019-02-01   NA        2
#3 2019-03-01   NA       NA


回答

更新:
感谢阿克伦!!!现在它起作用了!

data %>%  
  filter(if_all(where(is.numeric),  ~ . > 0)) %>% 
  mutate(i1 = A1 >= B1, i2 = A2 >= B2) %>% 
  group_by(Date) %>% 
  summarise(mean1 = mean(A1[i1] - B1[i1]), mean2 = mean(A2[i2] - B2[i2]))

输出:

  Date       mean1 mean2
  <date>     <dbl> <dbl>
1 2019-01-01   2.5     0
2 2019-02-01 NaN       2
3 2019-03-01 NaN     NaN

第一个版本
我几乎得到了 akrun 的解决方案。但不能处理负数

data %>% 
  group_by(Date) %>% 
  filter_if(is.numeric, all_vars((.) != 0)) %>% 
  filter(A1>=B1 | A2>=B2) %>% 
  summarise(mean1 = mean(A1-B1),
            mean2 = mean(A2-B2))

输出:

  Date       mean1 mean2
  <date>     <dbl> <dbl>
1 2019-01-01   2.5 -4.75
2 2019-02-01  -6    2   


以上是dplyr-用条件总结的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>