我想抽象出代码,总结课程学习模式和n个课程和n个学期的一群学生的成功率。
通过以下队列的学生,在参加“A”课程后,有多少人去了“B”课程,有多少学生成功了:
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
我们可以看到那些尝试过A课程的学生,那两个尝试过课程B,两个都成功了。
现在,我可以通过在summarise
声明(即completed_course_C = sum(course == "C" & success == 1)
)中添加线来计算课程“A”之后有多少课程“C”,但如果我有很多课程,那么它似乎不是最有效的选择。
此外,如果我想在课程“Y”之后总结课程“X”的顺序,对于任何“X”和“Y”,它会创建更多summarise
语句的排列。我如何看待那些在“Z”之后的“Y”之后取“X”的人。
那么,如何在不同数量的条款下总结不同数量的课程的课程进度和成功率?
我认为这是我的一些困难所在。我不知道结果data.frame
需要结构如何。
我知道我想轻松回答以下一般问题:
“X%的学生在课程中获得成功”A“,随后选修课程”B“,成功率为Y%”
我一直在尝试将一般问题(群组跟踪/排序?)应用到其他字段,以便在google和Stack Overflow中获得更好的关键词/搜索结果。一个似乎很有希望的是使用网络分析。
具体而言,this post, Network Analysis with R有助于确定潜在的解决方案。我按照这篇文章,使用我的数据,然后能够获得大约一半的信息。使用这种方法,我只能获得一系列尝试或一系列成功率 - 而不是两者兼而有之。但我刚开始学习网络分析。
实际上,我已经能够使用plotly
's sankey diagram手动可视化摘要,purrr
使用类似的网络/链接框架。但我仍然无法以编程方式计算该信息。
鉴于我想基本上将汇总函数“映射”到我的数据,我的许多尝试都使用了带有嵌套列表列的purrr
包。
data
attempts使用上面的原始# 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
除了关于Tracking cohort over time in R的许多其他人之外,我在寻找解决方案时引用了这些帖子,但没有一个是我想要的。
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
电话的输出:
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)
这里有一个关于你的问题的中间部分关于“X%的学生在课程中取得成功”A“,随后选修课程”B“并且成功率为Y%”。
这会找到每个课程成功的Y%,并且每个课程A都不成功。
> 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
结果:每个“事件1”作为一行,并且每列中的未来类Y的成功率。这表明服用A的人通过了所有后续课程,无论他们在A中如何做。服用B的人在C上的通过率为50-50。
qazxswpoi