Свернуть фрейм данных по группам, используя списки переменных для взвешенного среднего И суммы - PullRequest
0 голосов
/ 04 мая 2018

Я хочу свернуть следующий фрейм данных с использованием суммирования и взвешенных средних по группам.

У меня есть следующий фрейм данных

group_id = c(1,1,1,2,2,3,3,3,3,3)
var_1 = sample.int(20, 10)
var_2 = sample.int(20, 10)
var_percent_1 =rnorm(10,.5,.4)
var_percent_2 =rnorm(10,.5,.4)
weighting =sample.int(50, 10)

df_to_collapse = data.frame(group_id,var_1,var_2,var_percent_1,var_percent_2,weighting)

Я хочу свернуть свои данные в соответствии с группами, обозначенными group_id. Однако в моих данных у меня есть переменные в абсолютных уровнях (var_1, var_2) и в процентах (var_percent_1, var_percent_2).

Я создаю два списка для каждого типа переменных (мои реальные данные намного больше, что делает это необходимым). У меня также есть весовая переменная (weighting).

to_be_weighted =df_to_collapse[, 4:5]
to_be_summed = df_to_collapse[,2:3]

to_be_weighted_2=colnames(to_be_weighted)
to_be_summed_2=colnames(to_be_summed) 

И моя цель состоит в том, чтобы одновременно свернуть мои данные, используя итоговую сумму или средневзвешенное значение, в соответствии с типом переменной (то есть, если это в процентах, я использую средневзвешенное значение).

Вот моя лучшая попытка:

 df_to_collapse %>% group_by(group_id) %>% summarise_at(.vars = c(to_be_summed_2,to_be_weighted_2), .funs=c(sum, mean))

Но, как вы можете видеть, это не a средневзвешенное значение

Я пробовал много разных способов использования функции weighted.mean, но мне не повезло. Вот пример одной такой попытки:

df_to_collapse %>% group_by(group_id) %>% summarise_at(.vars = c(to_be_weighted_2,to_be_summed_2), .funs=c(weighted.mean(to_be_weighted_2, weighting), sum))

и соответствующая ошибка:

Error in weighted.mean.default(to_be_weighted_2, weighting) : 
'x' and 'w' must have the same length

1 Ответ

0 голосов
/ 04 мая 2018

Вот способ сделать это путем преобразования в длинные данные, добавления фиктивной переменной с именем type для определения процента (необязательно, но удобно), применения функции в summarise в зависимости от того, является ли это процентом, затем распространяясь обратно в широкую форму. Если вы можете изменить имена столбцов, вы можете придумать более элегантный способ создания столбца type, но это действительно больше для удобства.

Уловка для меня была type[1] == "percent"; Мне пришлось использовать [1], потому что все в каждой группе имеют один и тот же тип, но в противном случае == работает над каждым значением в векторе и выдает несколько логических значений, когда вам действительно нужно 1.

library(tidyverse)

set.seed(1234)
group_id = c(1,1,1,2,2,3,3,3,3,3)
var_1 = sample.int(20, 10)
var_2 = sample.int(20, 10)
var_percent_1 =rnorm(10,.5,.4)
var_percent_2 =rnorm(10,.5,.4)
weighting =sample.int(50, 10)

df_to_collapse <- data.frame(group_id,var_1,var_2,var_percent_1,var_percent_2,weighting)

df_to_collapse %>%
    gather(key = var, value = value, -group_id, -weighting) %>%
    mutate(type = ifelse(str_detect(var, "percent"), "percent", "int")) %>%
    group_by(group_id, var) %>%
    summarise(sum_or_avg = ifelse(type[1] == "percent", weighted.mean(value, weighting), sum(value))) %>%
    ungroup() %>%
    spread(key = var, value = sum_or_avg)
#> # A tibble: 3 x 5
#>   group_id var_1 var_2 var_percent_1 var_percent_2
#>      <dbl> <dbl> <dbl>         <dbl>         <dbl>
#> 1        1    26    31         0.269         0.483
#> 2        2    32    21         0.854         0.261
#> 3        3    29    49         0.461         0.262

Создано в 2018-05-04 пакетом Представ (v0.2.0).

...