在忽略dplyr链中特定的一组值时取平均值

时间:2019-07-11 14:58:37

标签: r dplyr

假设我有以下数据:

values = data.frame(score = c(1, 2, 3, 4, 5, 999, 2, 3, 999, 4),
                    score_2 = c(1, 4, 8 , 4, 999, 2, 3, 2, 1, 0))
values %>% 
  summarize(mean_score = mean(score),
            mean_score_2 = mean(score_2))

我想计算数据集中每个列的平均值,而忽略值“ 999”。

所以我可以做这样的事情:

values %>% 
  filter_all(all_vars(!grepl('999',.))) %>%
  summarize(mean_score = mean(score),
            mean_score_2 = mean(score_2))

但这将同时从score和score_2中删除第6、9和5行(因为这是999的位置)。在忽略某些值而又不消除整个行的情况下,如何有选择地计算均值?

对于score,结果输出应为3,对于score_2,结果输出应为2.78

2 个答案:

答案 0 :(得分:5)

我们可以使用summarise_allsummarise_if(仅用于选择numeric列),并通过比较运算符(!=)选择列值。

library(dplyr)
values %>%
     summarise_all(~ mean(.[.!= 999]))

如果有多个值,请使用%in%并取反!

values %>%
     summarise_all(~ mean(.[! . %in% c(999, 994)]))

答案 1 :(得分:2)

您也可以考虑以下内容:

values %>% 
    gather(key = "score_type", value = "val") %>% 
    filter(val != 999) %>% 
    group_by(score_type) %>% 
    summarise(mean_score = mean(val)) %>% 
    ungroup()

结果

# A tibble: 2 x 2
  score_type mean_score
  <chr>           <dbl>
1 score            3   
2 score_2          2.78

注释

恕我直言,该解决方案为您带来以下好处:

  • 使您更接近Tidy Data[PDF]处理dplyr中数据的思想。如果您打算按分数类型导出汇总统计信息,那么这似乎是首选的数据格式。

  • 您可以以可读的方式轻松扩展过滤器。如果要使用 ~ 表示法,最终将对附加操作执行以下操作:

    values %>%
        summarise_all(list( ~ mean(.[!. %in% c(999, 994)]), 
                            ~ max(.[!. %in% c(999, 994)])))
    

    这是不切实际的,因为对于更复杂的过滤器,您最终将不得不创建且仅出于该原因而带来并产生不可读的语句或向量。此外,结果的格式不正确

    #   score_mean score_2_mean score_max score_2_max
    # 1          3     2.777778         5           8