R - Суммируйте зачисление в курс по относительной последовательности терминов - PullRequest
3 голосов
/ 25 апреля 2019

Прикладная задача

Я хочу абстрагироваться от кода, который обобщает схемы прохождения курса и показатели успешности группы студентов для n курсов и n терминов.

Пример

Со следующей группой студентов, сколько человек пойдет на курс "B" после прохождения курса "A", и сколько из этих студентов преуспели:

data <- data.frame(student = c(1, 1, 1, 2, 2, 2, 3, 4, 4, 5, 5, 5),
                   term    = c(2, 3, 3, 1, 2, 3, 2, 1, 3, 1, 2, 4),
                   course  = c('A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C', 'A', 'A', 'C'),
                   success = c(1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1),
                   stringsAsFactors = FALSE)

Мы можем ответить на этот вопрос следующим кодом:

library(dplyr) 

# Get each student's first, second, third, ... term.
    data <- data %>%
      group_by(student) %>%
      mutate(term_dense = dense_rank(term))%>%
      ungroup()

# Identify those who took course A
    courseA <- data %>%
      filter(course == "A")%>%
      select(student, courseA_dense = term_dense)

# Get records of students who took course A, and their subsequent courses
    data <- data %>%
      left_join(courseA, by = "student")%>%
      filter(term_dense >= courseA_dense) # >= for courses they took in same term as course "A"

# Summarise for each term_dense
    data %>%
      group_by(term_dense) %>%
      summarise(attempted_course_A = sum(course == "A"),
                completed_course_A = sum(course == "A" & success == 1),
                attempted_course_B = sum(course == "B"),
                completed_course_B = sum(course == "B" & success == 1))

, который выдает:

# A tibble: 3 x 5
  term_dense attempted_course_A completed_course_A attempted_course_B completed_course_B
       <int>              <int>              <int>              <int>              <int>
1          1                  4                  2                  0                  0
2          2                  2                  2                  2                  2
3          3                  0                  0                  0                  0

, и мы можем видеть, что из студентов, которые пытались пройти курсА, это 2 попытки курса Б, оба из которых были успешными.

Теперь я могу вычислить, сколько человек взяло курс "С" после , пройдя курс "А", добавив строки в summarise утверждение (то есть completed_course_C = sum(course == "C" & success == 1)), но если у меня много курсов, это не кажется наиболее эффективным вариантом.

Кроме того, если я хочу обобщить последовательность курса "X" после курса «Y» для любых «X» и «Y» создается еще больше перестановокиз summarise заявлений.И как мне смотреть на тех, кто взял «X» после «Y» после «Z».

Итак, как мне суммировать прогресс курсаи показатели успешности для различного количества курсов по разному количеству терминов?

Желаемый результат

Я думаю, что именно в этом и заключаются некоторые из моих трудностей.Я не знаю, как должно получиться структурированное data.frame.

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

"X% студентов, которые были успешными в курсе" A ", впоследствии прошли курс" B "ипоказатель успешности Y% "

Абстрактная проблема

Я пытался применить общую проблему (отслеживание / последовательность когорт?) к другим полям, чтобы получить лучшие ключевые слова /Результаты поиска в Google и Stack Overflow.Тот, который казался многообещающим, использует сетевой анализ.

В частности, этот пост, Сетевой анализ с R , был полезен при определении потенциального решения.Я следовал этой статье, используя вместо этого мои данные, и смог получить около половины моей информации.Используя этот метод, я смог получить только последовательность попыток или последовательность успешных попыток - но не обе.Но я только начал изучать сетевой анализ.

На самом деле, я смог вручную визуализировать сводку, используя диаграмму Санки plotly , которая использует аналогичную сеть /рамки ссылок.Но я до сих пор не смог программно рассчитать эту информацию.

Другие попытки

Учитывая, что я хочу по существу «сопоставить» сводную функцию с моими данными, многие из моих попыток использовалипакет purrr с вложенными списками-столбцами.

purrr попыток

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

# library(dplyr) # Loaded in above example
library(tidyr)
library(purrr)    

data <- data %>%
      group_by(student) %>%
      mutate(term_dense = dense_rank(term)) %>%
      ungroup()%>%
      nest(term, course, success, .key = "schedule")

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

attempt_summary <- function(df, source, target){

  temp_df <- df %>%
                filter(map_lgl(schedule, ~any(.x$course == source)))%>%
                select(student, source_term_dense = term_dense)

  df <- df %>%
        left_join(temp_df, by = "student")%>%
        filter(term_dense >= source_term_dense)

  df %>%
    group_by(term_dense) %>%
    summarise(completed_source = sum(map_int(schedule, ~any(.x$course == source & .x$success == 1))),
              attempted_target = sum(map_int(schedule, ~any(.x$course == target))),
              completed_target = sum(map_int(schedule, ~any(.x$course == target & .x$success == 1))))

}

Функция работает для одного примера,

attempt_summary(data, "A", "B")

# A tibble: 3 x 4
  term_dense completed_source attempted_target completed_target
       <int>            <int>            <int>            <int>
1          1                2                0                0
2          2                2                2                2
3          3                0                0                0

, но я не мог понять, как сопоставить ее со всем остальным (я не могдаже понять, как структурировать мои списки целей и источников), но здесь была моя попытка:

# DO NOT RUN - DOESN'T WORK
# map(data, attempt_summary, source = src_list, target = trgt_list)

Сообщения переполнения стека

В дополнение ко многим другим о purrr, я ссылался на эти сообщенияв поиске решения, но ничего из того, что я искал, не было.

Информация о сеансе

Вот результат моего sessionInfo() звонка:

> sessionInfo()
R version 3.5.3 (2019-03-11)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 17763)

Matrix products: default

locale:
[1] LC_COLLATE=English_United States.1252  LC_CTYPE=English_United States.1252   
[3] LC_MONETARY=English_United States.1252 LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] purrr_0.3.2   tidyr_0.8.3   dplyr_0.8.0.1

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.1       fansi_0.4.0      utf8_1.1.4       crayon_1.3.4     assertthat_0.2.1 R6_2.4.0        
 [7] magrittr_1.5     pillar_1.3.1     cli_1.1.0        rlang_0.3.4      rstudioapi_0.10  tools_3.5.3     
[13] glue_1.3.1       compiler_3.5.3   pkgconfig_2.0.2  tidyselect_0.2.5 tibble_2.1.1    

1 Ответ

0 голосов
/ 26 апреля 2019

Вот один кусочек в вашем вопросе в середине о «X% студентов, которые успешно прошли курс« A », впоследствии прошли курс« B »и имели показатель успешности Y%».

Находит Y% для каждого успешного курса А и каждого неудачного курса А.

library(tidyverse)
data2 <- data %>%
  left_join(data, by = c("student")) %>%   # add future course results to each result that has any
  filter(term.y > term.x) %>%  # includes all future courses; could limit to just next one?
  count(course.x, success.x, course.y, success.y) %>%
  spread(success.y, n, fill = 0) %>%
  mutate(success_rate = `1`/ (`0` + `1`)) %>%
  select(course.x:course.y, success_rate) %>%
  spread(course.y, success_rate)

Результаты: каждое «событие 1» в виде строки и вероятность успеха для будущего класса Y в каждом столбце. Это показывает, что люди, которые взяли A, прошли все последующие курсы, независимо от того, как они прошли в A. Люди, которые взяли B, имели 50-50 баллов на C.

> data2
# A tibble: 3 x 5
  course.x success.x     A     B     C
  <chr>        <dbl> <dbl> <dbl> <dbl>
1 A                0     1    NA   1  
2 A                1    NA     1   1  
3 B                1    NA    NA   0.5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...