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_longer,filter/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