Я думаю, что эту проблему легче решить, если сначала немного переставить данные в соответствии с принципами «аккуратных данных» , где каждый раз, когда изменяется статус студента, записывается в отдельном ряду.Переставленные данные находятся в problem_wrangled
.
. Тогда текущий статус обычно можно определить, просматривая только самый последний статус, за исключением статуса «Завершено», для которого мы проверяем все прошлые статусы..
library(tidyverse)
problem <- tibble(name = c("Angela", "Claire", "Justin", "Bob", "Joseph", "Gil"),
status_1 = c("Registered", "Withdrawn", "Completed", "Registered", "Registered", "Registered"),
status_2 = c("Withdrawn", "Withdrawn", "Registered", "NA", "Withdrawn", "Cancelled"),
status_3 = c("NA", "Registered", "Withdrawn", "NA", "Registered", "NA"),
status_4 = c("Withdrawn", "Registered", "Withdrawn", "NA", "Registered", "NA"))
status_wrangled <- problem %>%
gather(key = "time", value = "status", starts_with("status")) %>%
mutate(time = as.integer(str_split_fixed(time, "_", 2)[, 2])) %>%
arrange(name, time) %>%
filter(status != "NA")
head(status_wrangled)
#> # A tibble: 6 x 3
#> name time status
#> <chr> <chr> <chr>
#> 1 Angela 1 Registered
#> 2 Angela 2 Withdrawn
#> 3 Angela 4 Withdrawn
#> 4 Bob 1 Registered
#> 5 Claire 1 Withdrawn
#> 6 Claire 2 Withdrawn
status_current <- status_wrangled %>%
group_by(name) %>%
summarize(
current = case_when(
# Has student completed at any time?
"Completed" %in% status ~ "Completed",
# Examine last recorded status
tail(status, 1) %in% c("Exempt", "Incomplete") ~ "Exclude",
tail(status, 1) %in% c("Withdrawn", "Cancelled", "No Show", "Denied", "Waitlist Expired") ~ "Not Taken",
tail(status, 1) == "Registered" ~ "Registered",
TRUE ~ "Unknown"
)
)
print(status_current, n = Inf)
#> # A tibble: 6 x 2
#> name current
#> <chr> <chr>
#> 1 Angela Not Taken
#> 2 Bob Registered
#> 3 Claire Registered
#> 4 Gil Not Taken
#> 5 Joseph Registered
#> 6 Justin Completed
Создано в 2019-06-17 пакетом представ (v0.3.0)
РЕДАКТИРОВАТЬ: Относительно вашего комментария оВыполнение приблизительных совпадений: я изменил пример, чтобы разрешить приблизительные совпадения до определенного расстояния редактирования.Вы, вероятно, хотите настроить это, но допустимо до трех или около того правок.Но будьте осторожны, разница между «Incomplete» и «Completed» составляет всего четыре правки.
library(tidyverse)
problem <- tibble(name = c("Angela", "Claire", "Justin", "Bob", "Joseph", "Gil"),
status_1 = c("Registered", "Withdrawn", "Completed", "Registered", "Registered", "Registered"),
status_2 = c("Withdrawn", "Withdrawn", "Registered", "NA", "Withdrawn", "Cancelled"),
status_3 = c("NA", "Registered", "Withdrawn", "NA", "Registered", "NA"),
status_4 = c("Withdrawnn", "Registered", "Withdrawn", "NA", "Registered", "NA"))
status_wrangled <- problem %>%
gather(key = "time", value = "status", starts_with("status")) %>%
mutate(time = as.integer(str_split_fixed(time, "_", 2)[, 2])) %>%
arrange(name, time) %>%
filter(status != "NA")
# Find if input vector matches to *any* given pattern below the specified edit distance
any_fuzzy_match <- function(x, patterns, max.distance = 3) {
matches <- map(paste0("^", patterns, "$"), agrepl, x = x, max.distance = max.distance, fixed = FALSE)
reduce(matches, `|`)
}
status_current <- status_wrangled %>%
group_by(name) %>%
summarize(
current = case_when(
# Has student completed at any time?
any(any_fuzzy_match(status, "Completed")) ~ "Completed",
# Examine last recorded status
any_fuzzy_match(tail(status, 1), c("Exempt", "Incomplete")) ~ "Exclude",
any_fuzzy_match(tail(status, 1), c("Withdrawn", "Cancelled", "No Show", "Denied", "Waitlist Expired")) ~ "Not Taken",
any_fuzzy_match(tail(status, 1), "Registered") ~ "Registered",
TRUE ~ "Unknown"
)
)
print(status_current, n = Inf)
#> # A tibble: 6 x 2
#> name current
#> <chr> <chr>
#> 1 Angela Not Taken
#> 2 Bob Registered
#> 3 Claire Registered
#> 4 Gil Not Taken
#> 5 Joseph Registered
#> 6 Justin Completed
Создан в 2019-06-18 пакетом Представить (v0.3.0)