使用group_by搭配用户自定义函数
我写了一个函数来计算有多少学生升入高等教育(HE)的比例。现在我想以不同的方式筛选和分组我的数据,并计算每个分组中升入高等教育的比例。
同一个学生在列表中会出现多次,同时也有尚未参与的学生,这些人不应被计入。
example <- tibble(Student.ID = c("#001","#002","#003","#004","#005"),
Student.Attended = c("Yes", "Yes", "No", "Yes", "Yes"),
entryby19 = c("Yes", "Yes", "Yes", "Yes", "No"),
Type = c("Exhibition", "Exhibition", "Mentoring", "Mentoring", "Mentoring"))
progressionby19 <- function(.data) {
total <- .data %>%
filter(Student.Attended == "Yes") %>%
summarise(count = n_distinct(Student.ID))
progressed <- .data %>%
filter(Student.Attended == "Yes") %>%
filter(entryby19 == "Yes") %>%
summarise(count = n_distinct(Student.ID))
(progressed/total)*100
}
progressionby19(example)
example %>%
group_by(Type) %>%
summarise(learner_count = n_distinct(Student.ID),
progression_rate = progressionby19(.))
然而,当我接着对数据进行分组时,出现了一个错误。我花了不少时间来寻找解决方法,并把下面的代码添加到了函数中(大致是直接从我找到的地方复制粘贴过来)。我并不百分之百理解它在做什么,但以这种方式运行时,几乎能工作——只是好像把进展率与其他部分分开分组了。
progressionby19 <- function(.data) {
if (dplyr::is_grouped_df(.data)) {
return(dplyr::do(.data, progressionby19(.)))
}
total <- .data %>%
filter(Student.Attended == "Yes") %>%
summarise(count = n_distinct(Student.ID))
progressed <- .data %>%
filter(Student.Attended == "Yes") %>%
filter(entryby19 == "Yes") %>%
summarise(count = n_distinct(Student.ID))
(progressed/total)*100
}
progressionby19(example)
example %>%
group_by(Type) %>%
summarise(learner_count = n_distinct(Student.ID),
progression_rate = progressionby19(.))
有人能帮我把它理清楚吗?
解决方案
我不太清楚你期望的结果具体是怎样的,但也许这对你会有帮助。正如我在第一条注释中所建议的,dplyr 的 group_xxxx 家族函数很可能是要走的方向。在这种情况下,group_modify 可能比 group_map 稍微高效一些。(group_map 仍然可以工作,但你需要在管道中添加 bind_rows 才能得到相同的结果。)
The group_xxxx 家族的函数将一个由 group_xxx 的参数定义的函数应用于分组数据框的每个分组。若数据框未分组,则该函数应用于整个数据框。
用户提供的函数需要定义两个参数,通常命名为 .x 和 .y。.x 是输入数据框的当前分组。.y 是一个包含当前分组定义的单行数据框。我认为这里不需要使用 .y,但我们仍然需要对它进行定义。
因此,在尽量少改动你的函数的前提下(虽然如果是我来写,还会做其他修改……),你可以写成
library(tidyverse)
progressionby19 <- function(.x, .y) {
total <- .x %>%
filter(Student.Attended == "Yes") %>%
summarise(count = n_distinct(Student.ID))
progressed <- .x %>%
filter(
Student.Attended == "Yes",
entryby19 == "Yes"
) %>%
summarise(count = n_distinct(Student.ID))
total %>% mutate(progression_rate = (progressed$count/total$count)*100)
}
然后使用 group_modify 来应用该函数:
example %>%
group_by(Type) %>%
group_modify(progressionby19)
得到
# A tibble: 2 × 3
# Groups: Type [2]
Type count progression_rate
<chr> <int> <dbl>
1 Exhibition 2 100
2 Mentoring 2 50
这有点接近你想要的结果吗?如果不是,你确实需要提供更多信息……
附言
下面的函数给出的结果与上面的相同,但在我看来更易于理解。
progressionby19 <- function(.x, .y) {
.x %>%
filter(Student.Attended == "Yes") %>%
summarise(
count = n(),
progression_rate = 100 * mean(entryby19 == "Yes")
)
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。