программно создавать новые переменные, которые являются суммами вложенных рядов других переменных - PullRequest
0 голосов
/ 26 августа 2018

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

df <- data_frame(group = c("A", "B"),
             no.highschool = c(20, 10),
             high.school = c(70,40),
             college = c(10, 40),
             graduate = c(0,10))

df
    # A tibble: 2 x 5
  group no.highschool high.school college graduate
  <chr>         <dbl>       <dbl>   <dbl>    <dbl>
1 A               20.         70.     10.       0.
2 B               10.         40.     40.      10.

Например, в группе А 70% людей имеют высшее образование.

Я хочу сгенерировать 4 переменные, которые дают мне долю людей в каждой группе с менее чем каждым из 4 уровней образования (например, lessthan_no.highschool, lessthan_high.school и т. Д.).

желаемый df будет:

desired.df <- data.frame(group = c("A", "B"),
                     no.highschool = c(20, 10),
                     high.school = c(70,40),
                     college = c(10, 40),
                     graduate = c(0,10),
                     lessthan_no.highschool = c(0,0),
                     lessthan_high.school = c(20, 10),
                     lessthan_college = c(90, 50),
                     lessthan_graduate = c(100, 90))

По моим фактическим данным, у меня много групп и гораздо больше уровней образования. Конечно, я мог бы делать это по одной переменной за раз, но как я мог сделать это программно (и элегантно), используя tidyverse инструменты?

Я бы начал с того, что сделал что-то вроде mutate_at() внутри map(), но меня смутило то, что список суммируемых переменных различен для каждой из новых переменных. Вы можете передать список новых переменных и их соответствующих переменных для суммирования в виде двух списков в pmap(), но не ясно, как сгенерировать этот второй список кратко. Хотите знать, если есть какое-то решение для вложения ...

Ответы [ 2 ]

0 голосов
/ 26 августа 2018

Вот базовое решение R.Хотя вопрос требует tidyverse, учитывая диалог в комментариях к вопросу, я решил опубликовать его.
Он использует apply и cumsum для выполнения тяжелой работы.Затем есть некоторые косметические проблемы, прежде чем cbind войдет в конечный результат.

tmp <- apply(df[-1], 1, function(x){
    s <- cumsum(x)
    100*c(0, s[-length(s)])/sum(x)
})
rownames(tmp) <- paste("lessthan", names(df)[-1], sep = "_")
desired.df <- cbind(df, t(tmp))

desired.df
#  group no.highschool high.school college graduate lessthan_no.highschool
#1     A            20          70      10        0                      0
#2     B            10          40      40       10                      0
#  lessthan_high.school lessthan_college lessthan_graduate
#1                   20               90               100
#2                   10               50                90
0 голосов
/ 26 августа 2018

как я могу сделать это программно (и элегантно), используя инструменты Tidyverse?

Определенно, первый шаг - привести в порядок ваши данные.Информация о кодировке (например, уровень edu) в именах столбцов не аккуратно .Когда вы конвертируете education в коэффициент, убедитесь, что уровни находятся в правильном порядке - я использовал порядок, в котором они появились в именах столбцов исходных данных.

library(tidyr)
tidy_result = df %>% gather(key = "education", value = "n", -group) %>%
  mutate(education = factor(education, levels = names(df)[-1])) %>%
  group_by(group) %>%
  mutate(lessthan_x = lag(cumsum(n), default = 0) / sum(n) * 100) %>%
  arrange(group, education)
tidy_result
# # A tibble: 8 x 4
# # Groups:   group [2]
#   group education         n lessthan_x
#   <chr> <fct>         <dbl>      <dbl>
# 1 A     no.highschool    20          0
# 2 A     high.school      70         20
# 3 A     college          10         90
# 4 A     graduate          0        100
# 5 B     no.highschool    10          0
# 6 B     high.school      40         10
# 7 B     college          40         50
# 8 B     graduate         10         90

Это дает нам хороший результат,аккуратный результат.Если вы хотите spread / cast эти данные в формате unidid desired.df, я бы порекомендовал использовать data.table::dcast, поскольку (насколько мне известно) tidyverse не предлагает хороший способ разбить несколько столбцов.См. Распределение нескольких столбцов с помощью tidyr или Как я могу распространить повторные измерения нескольких переменных в широкоформатный формат? для решения data.table или неэлегичной версии tidyr / dplyr.Перед распространением вы можете создать ключ less_than_x_key = paste("lessthan", education, sep = "_").

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...