У меня есть фреймворк, который суммирует количество раз, когда птиц наблюдали в месте их размножения один раз в день и каждый час в дневное время (то есть, когда солнце находилось над горизонтом). пример:
head(df)
ID site day hr nObs
1 19 A 202 11 60
2 19 A 202 13 18
3 19 A 202 15 27
4 8 B 188 8 6
5 8 B 188 9 6
6 8 B 188 11 7
Однако этот фреймворк не включает часы, когда за птицей не наблюдали. Например. нет строки для птицы 19 на 202 день в 14 со значением nObs, равным 0.
Я хотел бы найти способ, желательно с помощью dplyr (аккуратный стих), чтобы добавить в эти строки, когда люди не наблюдаются.
Один из способов сделать это - сначала создать «шаблон» всех возможных комбинаций, по которым можно наблюдать за птицами, а затем объединить («левое соединение») фактические наблюдения в этот шаблон:
a = read.table(text = " ID site day hr nObs
1 19 A 202 11 60
2 19 A 202 13 18
3 19 A 202 15 27
4 8 B 188 8 6
5 8 B 188 9 6
6 8 B 188 11 7")
tpl <- expand.grid(c(unique(a[, 1:3]), list(hr = 1:24)))
merge(tpl, a, all.x = TRUE)
Отредактируйте на основе комментария @ user3220999: в случае, если мы хотим выполнить процесс для каждого ID
, мы можем просто использовать split
, чтобы получить список data.frames для каждого идентификатора, получить список шаблонов и объединить mapply
в двух списках:
a <- split(a, a$ID)
tpl <- lapply(a, function(ai) {
expand.grid(c(unique(ai[, 1:3]), list(hr = 1:24)))
})
res <- mapply(merge, tpl, a, SIMPLIFY = FALSE, MoreArgs = list(all.x = TRUE))
Я действительно думал об этом, но наша выборка была очень изменчивой в течение трехмесячного сезона, поэтому ее, вероятно, придется настраивать для каждого человека.
Я отредактировал свой ответ, чтобы он был применим к каждому идентификатору, мы, конечно, могли бы использовать аналогичный подход с другими разделениями.
Вы можете использовать complete
из tidyr
, т.е.
library(tidyverse)
df %>%
group_by(ID, site) %>%
complete(hr = seq(min(hr), max(hr)))
который дает,
# A tibble: 9 x 5 # Groups: ID, site [2] ID site hr day nObs <int> <fct> <int> <int> <int> 1 8 B 8 188 6 2 8 B 9 188 6 3 8 B 10 NA NA 4 8 B 11 188 7 5 19 A 11 202 60 6 19 A 12 NA NA 7 19 A 13 202 18 8 19 A 14 NA NA 9 19 A 15 202 27
df %>% group_by(ID, site, day) %>% complete(hr = seq(min(hr), max(hr)), fill = list(nObs = 0))
может больше соответствовать потенциальному ожидаемому результату (хотя, конечно, у нас нет возможности знать это).
Спасибо @ arg0naut, ваше дополнение отлично работает, заменяя все NA на 0.
Связанный: Заполнение пропущенных дат в сгруппированном временном ряду - аккуратный способ?; Самый быстрый способ добавить строки для отсутствующих значений в data.frame?