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

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

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(), но не совсем очевидно, как сгенерировать этот второй список в сжатой форме. Интересно, есть ли какое-нибудь решение для гнездования ...

нет уровня ниже no.highschool, поэтому lessthan_no.highschool всегда будет 0.

lost 26.08.2018 05:52

В desired.df у вас есть переменная less.than.hs. Разве это не должно быть no.highschool?

Rui Barradas 26.08.2018 06:27

не уверен о чем ты?

lost 26.08.2018 06:29

@lost Gregor превзошел меня, в желаемом результате вы повторяете переменные вашего ввода, поэтому их имена должны быть одинаковыми. Одного из них нет. Я решил, что это опечатка. О, и я пропустил часть о tidyverse, поэтому я был занят кодированием базового R-способа. Будет ли это интересно?

Rui Barradas 26.08.2018 06:37

это была опечатка, извините. Зафиксированный.

lost 26.08.2018 06:44

@RuiBarradas, базовый метод R меня сейчас не интересует, но, если вы уже начали его использовать, возможно, это может быть кто-то другой, кто найдет это позже :)

lost 26.08.2018 06:46

Хорошо, я отправлю ответ.

Rui Barradas 26.08.2018 07:05
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

how could I do this programatically (and elegantly) using tidyverse tools?

Определенно, первым делом нужно привести данные в порядок. Информация о кодировании (например, уровень 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 в ваш неупорядоченный формат desired.df, я бы порекомендовал использовать data.table::dcast, поскольку (насколько мне известно) тидиверс не предлагает удобного способа распределения нескольких столбцов. См. Распространение нескольких столбцов с помощью tidyr или Как я могу распределить повторяющиеся измерения нескольких переменных в широком формате? для решения data.table или неэлегантной версии tidyr / dplyr. Перед распространением можно было создать ключ less_than_x_key = paste("lessthan", education, sep = "_").

это намеренно в неаккуратном формате. Он в этом формате, потому что он будет присоединен к данным индивидуального уровня, которые находятся в аккуратном формате и которые будут использоваться для моделирования и т. д.

lost 26.08.2018 06:34

Отлично. Но если вы хотите «элегантно» использовать инструменты tidyverse, вам нужно сначала привести их в порядок. И вопросы, на которые я ссылался, должны помочь вам вернуть его в нужный вам нестандартный формат. Я не думаю, что мне нужно здесь повторять эти ответы. Если есть изменения или обновления, следует обновить те вопросы, которые касаются этой части проблемы.

Gregor Thomas 26.08.2018 06:37

Это работает, хотя порядок переменных отличается от OP: желаемый.df <- tidy_result%>% select (-n)%>% mutate (education = paste0 ("lessthan_", education))%>% spread (education , меньшее_x)%>% right_join (df)

lost 26.08.2018 07:02

Вот базовое решение 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

Другие вопросы по теме