Использование mutate () и пакета srvyr для расчета процентов в опросе с весами - почему R возвращает ошибку? - PullRequest
0 голосов
/ 21 февраля 2019

Я недавно начал работать с r и srvyr.В настоящее время я борюсь со следующей проблемой:

Я хотел бы рассчитать проценты в взвешенном опросе для некоторых групп.Моя переменная интереса здесь - "вызов".Мой фрейм данных (df) выглядит примерно так:

df <- read.table(text=" 
          educ     call     wealth     x     y      z 
A           1        0          1       20    12   0.9
B           3        0          2       21    13   0.8
C           5        1          3       22    14   1.1
D           2        0          2       23    12   0.8 
E           1        1          1       24    16   0.92", header=T)`
 library(srvyr)

 survey_design <- df %>% 
              as_survey_design(ids = x, strata = y, weights = z)

 syv2 <- survey_design %>% 
 group_by(educ) %>%
 mutate(call_rate = n / sum(n)) %>%
 filter(call == 1) %>%
 select(educ, call_rate)

Когда я пробую этот код, я получаю следующую ошибку: Ошибка в mutate_impl (.data, dots): Ошибка оценки: не числоваяаргумент бинарного оператора.

Однако, без использования srvyr, я не получаю эту ошибку.

Я пробовал код для нескольких переменных.

1 По сути, я ищу самый простой способ вычислить процентное соотношение подгрупп по столбцам / переменным в srvyr.Большинство моих переменных являются двоичными.

2 Существует ли элегантный способ выполнить эту операцию для нескольких переменных.Я хотел бы использовать переменную call все время, но посмотрите на другие подгруппы в других переменных (educ здесь только один пример)?

3 Возможно лиобъединить пакет srvyr с TableOne для вычисления абсолютных чисел / процентов и доверительных интервалов 95%?

Есть предложения?

Ответы [ 2 ]

0 голосов
/ 23 февраля 2019

автор srvyr здесь (нашел это с помощью тщеславного поиска).Ответ @symbolrush может избежать ошибки, но для расчета таких пропорций и учета весов опроса вы захотите использовать функцию summarize() вместо mutate() + filter()

IВерьте, что вы действительно хотите:

df <- read.table(text="         educ     call     wealth     x     y      z 
A           1        0          1       20    12   0.9
B           3        0          2       21    13   0.8
C           5        1          3       22    14   1.1
D           2        0          2       23    12   0.8 
E           1        1          1       24    16   0.92", header=T)
library(srvyr)
#> 
#> Attaching package: 'srvyr'
#> The following object is masked from 'package:stats':
#> 
#>     filter

# required because your example dataset's weights aren't structured like real data
options(survey.lonely.psu="remove") 


survey_design <- df %>% 
  as_survey_design(ids = x, strata = y, weights = z)

syv2 <- survey_design %>% 
  group_by(educ) %>%
  summarize(call = survey_mean(call))

syv2
#> # A tibble: 4 x 3
#>    educ  call call_se
#>   <int> <dbl>   <dbl>
#> 1     1 0.505   0.250
#> 2     2 0       0    
#> 3     3 0       0    
#> 4     5 1       0

# Need to use something like purrr::map (or lapply) to iterate over different grouping variables
library(purrr)
syv3 <- map_dfr(c("educ", "wealth"), function(grp_var) {
  survey_design %>% 
    group_by_at(grp_var) %>% 
    summarize(result = survey_mean(call)) %>% 
    rename(group_level = !!grp_var) %>% 
    mutate(group_var = grp_var) %>%
    select(group_var, group_level, result, result_se)
})
syv3
#> # A tibble: 7 x 4
#>   group_var group_level result result_se
#>   <chr>           <int>  <dbl>     <dbl>
#> 1 educ                1  0.505     0.250
#> 2 educ                2  0         0    
#> 3 educ                3  0         0    
#> 4 educ                5  1         0    
#> 5 wealth              1  0.505     0.250
#> 6 wealth              2  0         0    
#> 7 wealth              3  1         0

# This is almost a case where you could use  dplyr's scoped functions to
# perform mean on a lot of vars, but only works if you're iterating over
# the variable you're calculating a mean on.
syv4 <- survey_design %>% 
  group_by(educ) %>%
  summarize_at(vars(call, wealth), ~survey_mean(.))

syv4
#> # A tibble: 4 x 5
#>    educ  call call_se wealth wealth_se
#>   <int> <dbl>   <dbl>  <dbl>     <dbl>
#> 1     1 0.505   0.250      1         0
#> 2     2 0       0          2         0
#> 3     3 0       0          2         0
#> 4     5 1       0          3         0

Создано в 2019-02-22 с помощью представительного пакета (v0.2.1)

Обновление

@ GregF: возможно ли использовать код в syv3 и получать эти результаты при разбиении столбцов результатов на (а) всего = мужчина + женщина, (б) женщина и (с) мужчина?- msgh

Переключение источников данных на источник, включенный в пакет опроса (поскольку в данных примера не хватало переменных).Переменные, которые заменяют те из старого примера:

  • stype & sch.wide -> Education & wealth
  • api99 -> call
  • yr.rnd -> sex
library(srvyr)
#> 
#> Attaching package: 'srvyr'
#> The following object is masked from 'package:stats':
#> 
#>     filter
library(purrr)
data(api, package = "survey")

dstrata <- apistrat %>%
  as_survey(strata = stype, weights = pw)

syv5 <- map_dfr(c("stype", "sch.wide"), function(grp_var) {
  dstrata %>% 
    group_by_at(c(grp_var)) %>% 
    summarize(
      result_yr = survey_mean(ifelse(yr.rnd == "Yes", api99, NA), na.rm = TRUE),
      result_nonyr = survey_mean(ifelse(yr.rnd == "No", api99, NA), na.rm = TRUE),                      
      result = survey_mean(api99)
    ) %>% 
    rename(group_level = !!grp_var) %>% 
    mutate_if(is.factor, as.character) %>% 
    mutate(group_var = grp_var) %>%
    select(group_var, group_level, dplyr::starts_with("result"))
})

syv5
#> # A tibble: 5 x 8
#>   group_var group_level result_yr result_yr_se result_nonyr result_nonyr_se
#>   <chr>     <chr>           <dbl>        <dbl>        <dbl>           <dbl>
#> 1 stype     E                528.         22.7         660.            14.2
#> 2 stype     H                484           0           620.            15.9
#> 3 stype     M                506.         49.6         615.            17.0
#> 4 sch.wide  No               426.         17.8         611.            18.5
#> 5 sch.wide  Yes              536.         22.2         654.            12.0
#> # ... with 2 more variables: result <dbl>, result_se <dbl>

Создано в 2019-02-28 пакетом представлением (v0.2.1)

Обновление2 : возможно ли объединить TableOne + пакет srvyr для получения абсолютных чисел, процентов и доверительных интервалов?Я понял, что это было бы намного проще.

0 голосов
/ 21 февраля 2019

Попробуйте изменить mutate(call_rate = n() / sum(n()) и убедитесь, что все переменные представлены числовыми.Вы можете привести символьные переменные, содержащие числа, к числовому представлению, используя as.numeric в каждом столбце.


TL; DR:

, поскольку n являетсяФункция, вызывающая n внутри вашего кода, возвращает closure (примерно это означает, что она возвращает источник функции) вместо фактического вызова этой функции.

Посмотрите на следующий минимальный пример:

library(dplyr)
mtcars %>% mutate(freq = n / sum(n))

это возвращает ошибку:

Ошибка в mutate_impl (.data, dots): Ошибка оценки: недопустимый тип (закрытие) аргумента.

тогда как

library(dplyr)
mtcars %>% mutate(freq = n() / sum(n()))

фактически выполняется.

Или просто наберите dplyr::n в консоли, и вы увидите тело этой функции:

function () 
{
    abort("This function should not be called directly")
}
<environment: namespace:dplyr>
...