【问题标题】:Using dplyr summarise_if() with a predicate将 dplyr summarise_if() 与谓词一起使用
【发布时间】:2019-08-26 13:07:37
【问题描述】:

我想计算 x1 和 x2 在 sum(is.NA) 与所有观察值之比 >= 0.5 或 NA 的日子的平均值。

数据:

library(lubridate)
library(dplyr)

x = seq(length.out= 10)
x[seq(1,11,5)] <- NA
data = data.frame(
    tseq = seq(from = Sys.time(), length.out = 11, by = "12 hours"),
    x1 = x,
    x2 = x
    )

means = data %>% group_by(tseq=floor_date(tseq, "days")) %>%
    summarise_all(list( mean = ~ mean(., na.rm = TRUE)))

ratio = data %>% group_by(tseq=floor_date(tseq, "days")) %>%
    summarise_all(list( ratio = ~ sum(is.na(.)) / n()))
> ratio
  tseq                x1_ratio x2_ratio
1 2019-08-26 00:00:00      1        1  
2 2019-08-27 00:00:00      0        0  
3 2019-08-28 00:00:00      0        0  
4 2019-08-29 00:00:00      0.5      0.5
5 2019-08-30 00:00:00      0        0  
6 2019-08-31 00:00:00      0.5      0.5

所以这里 2019-08-26, 2019-08-29, 2019-08-31 日期会得到手段。 在向量中,我可以通过函数完成此操作

isEnough = function(x){
    # is there enough values to calculate mean
    if (sum(is.na(x)) / length(x) < 0.5){
        return(FALSE)
    }
    else return(TRUE)
}

对于数据框,我找不到解决方案。到目前为止我已经尝试过

data %>% group_by(tseq=floor_date(tseq, "days")) %>%
    summarise_if(.predicate =  isEnough(~ sum(is.na(.)), ~n()),
    .funs = list( mean = ~ mean(., na.rm = TRUE)))
Error in naCount/xLength : non-numeric argument to binary operator

data %>% group_by(tseq=floor_date(tseq, "days")) %>%
    summarise_if(.predicate = list( ~ sum(is.na(.)) / n() > 0.5),
    .func = list( mean = ~ mean(., na.rm = TRUE)))
Error: n() should only be called in a data context

data %>% group_by(tseq=floor_date(tseq, "days")) %>%
    summarise_if(.predicate = (~ sum(is.na(.)) / ~n() > 0.5),
    .func = list( mean = ~ mean(., na.rm = TRUE)))
Error in sum(is.na(.))/~n() > 0.5 : 
  non-numeric argument to binary operator

【问题讨论】:

  • 我认为您还需要为数字列创建条件summarise_if(~is.numeric(.) &amp;&amp;)
  • 对于复杂的谓词,我总是发现创建一个布尔列更容易,按它过滤,然后使用普通的汇总。它更长,但在 6 个月内更容易解释。
  • @AmitKohli 感谢您的建议!我创建了一个布尔数据框,但我该如何过滤呢? ratio[-1] = ratio[-1] >= 0.5
  • 你会使用dplyr::filter()动词......所以在你的情况下,你会做data %&gt;% filter(ratio &gt;= 0.5)或类似的东西,我不确定你的情况:)

标签: r group-by dplyr summarize


【解决方案1】:

summarise_if 用于选择。将其视为summarise_at 的派生词,您可以在其中指定要在哪些列上使用某些函数。

您似乎想计算x1x2 的平均值分别,但在相同条件下,我首先使用tidyr'将两列合二为一sgather:

library(tidyr)
data %>% gather(x, val, x1, x2) %>% 
  group_by(tseqs=floor_date(tseq, "days"), x) %>% 
  summarise(
    ratio=sum(is.na(val))/n(), 
    mean=mean(val, na.rm=TRUE)*ifelse(ratio >= 0.5, NA, 1)
  )
# A tibble: 12 x 4
# Groups:   tseqs [?]
   tseqs               x     ratio  mean
   <dttm>              <chr> <dbl> <dbl>
 1 2019-08-26 00:00:00 x1      1   NaN  
 2 2019-08-26 00:00:00 x2      1   NaN  
 3 2019-08-27 00:00:00 x1      0     2.5
 4 2019-08-27 00:00:00 x2      0     2.5
 5 2019-08-28 00:00:00 x1      0     4.5
 6 2019-08-28 00:00:00 x2      0     4.5
 7 2019-08-29 00:00:00 x1      0.5  NA  
 8 2019-08-29 00:00:00 x2      0.5  NA  
 9 2019-08-30 00:00:00 x1      0     8.5
10 2019-08-30 00:00:00 x2      0     8.5
11 2019-08-31 00:00:00 x1      0.5  NA  
12 2019-08-31 00:00:00 x2      0.5  NA  

最后一步是清理它,并将其打包回格式:

data %>% gather(x, val, x1, x2) %>% 
  group_by(tseqs=floor_date(tseq, "days"), x) %>% 
  summarise(
    ratio=sum(is.na(val))/n(), 
    mean=mean(val, na.rm=TRUE)*ifelse(ratio >= 0.5, NA, 1)
  ) %>%
  select(tseqs, x, mean) %>%
  tidyr::spread(x, mean)
# A tibble: 6 x 3
# Groups:   tseqs [6]
  tseqs                  x1    x2
  <dttm>              <dbl> <dbl>
1 2019-08-26 00:00:00 NaN   NaN  
2 2019-08-27 00:00:00   2.5   2.5
3 2019-08-28 00:00:00   4.5   4.5
4 2019-08-29 00:00:00  NA    NA  
5 2019-08-30 00:00:00   8.5   8.5
6 2019-08-31 00:00:00  NA    NA  

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-23
    • 2018-04-02
    • 2021-07-28
    • 1970-01-01
    • 2013-01-31
    • 2011-07-29
    • 1970-01-01
    • 2021-01-19
    相关资源
    最近更新 更多