Dplyr вычисляет среднее значение и дисперсию без всех данных

У меня есть набор данных, который начинался следующим образом:

set.seed(50)
n <- 20
s_num <- c(10,20,30)
counts <- c(0,1,2,3,4)

strata <- sample(s_num, n, replace=T)
sites <- seq(1, n, by=1)
observed <- sample(counts, n, replace=T)

df <- as.data.frame(cbind(strata,sites,observed))

Я могу сгруппировать по слоям и получить средние значения и дисперсию с помощью dplyr:

library(dplyr)
df2 <- df %>%
  group_by(strata) %>%
  summarise(mcount = mean(observed),
            varcount = var(observed))

Проблема в том, что 0 счетчиков больше нет в базе данных:

df3 <- subset(df,observed != 0)

Таким образом, среднее значение и дисперсия теперь неверны:

df4 <- df3 %>%
  group_by(strata) %>%
  summarise(mcount = mean(observed),
            varcount = var(observed))

Но у меня есть количество сайтов:

site_count <- df %>%
  group_by(strata) %>%
  summarise(count_plot = n_distinct(sites))

Могу ли я по-прежнему использовать dplyr для расчета средней дисперсии без нулей? Среднее на самом деле не так уж сложно, объединив количество сайтов с df; дисперсия сложнее. Я могу добавить обратно 0 строк, если это необходимо, но хотел посмотреть, есть ли простой способ обойти это, если это возможно. Спасибо.


person tjr    schedule 20.06.2018    source источник


Ответы (3)


Вы можете вручную рассчитать среднее значение и дисперсию по формулам, как только вы count_plot вычислите.

Дисперсия рассчитывается как sum((x - mean(x))^2)/(length(x) - 1)

df3 %>% 
  left_join(site_count) %>% 
  group_by(strata) %>%
  summarise(N        = unique(count_plot),
            mcount   = sum(observed)/N,
            varcount = sum((observed - mcount)^2, (N - n())*mcount^2)/(N - 1)) %>% 
  select(-N)


# # A tibble: 3 x 3
#   strata mcount varcount
#    <dbl>  <dbl>    <dbl>
# 1   10.0   1.89    0.861
# 2   20.0   1.33    1.07 
# 3   30.0   2.40    2.30 

Что соответствует df2

df2

# A tibble: 3 x 3
  strata mcount varcount
   <dbl>  <dbl>    <dbl>
1   10.0   1.89    0.861
2   20.0   1.33    1.07 
3   30.0   2.40    2.30 
person IceCreamToucan    schedule 20.06.2018
comment
Большое спасибо. Я не был уверен, что sum(()) будет работать для каждой строки, но это работает. - person tjr; 20.06.2018

Вы можете добавить filter в свой конвейер.

df2 <- df %>%
 filter(observed != 0) %>%
 group_by(strata) %>%
 summarise(mcount = mean(observed),
          varcount = var(observed))

Таким образом, вам не нужно создавать промежуточный кадр данных.

person Adarsh Chavakula    schedule 20.06.2018
comment
Этот более элегантный - person akrun; 20.06.2018
comment
Из того, что я могу сказать, вопрос заключается в том, как рассчитать среднее значение и дисперсию без использования df - person IceCreamToucan; 20.06.2018
comment
Да, извините, я не ясно выразился. В этом случае у меня нет оригинального df. - person tjr; 20.06.2018

Мы можем создать логическое условие для подмножества

df %>%
   mutate(ind = observed != 0) %>%
   group_by(strata) %>%
   summarise(mcount = mean(observed[ind]), varcount = var(observed[ind]))
# A tibble: 3 x 3
#  strata mcount varcount
#   <dbl>  <dbl>    <dbl>
#1     10   1.89    0.861
#2     20   1.6     0.8  
#3     30   3       0.667

ПРИМЕЧАНИЕ. Использование as.data.frame(cbind не рекомендуется, поскольку cbind может преобразовать его в matrix (матрица может содержать только один класс), и это приведет к тому, что все столбцы будут factor или character с as.data.frame (если есть столбцы символов). Вместо этого используйте data.frame(strata, sites, observed)

person akrun    schedule 20.06.2018