Наша метеостанция записывала ежедневные данные о погоде (около 7 рядов/наблюдений) в неделю. Мы собирали данные о заболеваниях один раз в неделю (одно наблюдение/ряд в неделю). Как я могу соединить последнюю строку weather_df с disease_df, оставив другие ячейки пустыми? Я пробовал использовать left_join, но он неправильно добавляет одно значение из disease_df ко всем дням недели вместо записи данных о заболевании в конце недели.
Воспроизводимый пример
weather_df <- structure(list(week = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), levels = c("1", "2"), class = "factor"),
date = structure(c(1401062400, 1401148800, 1401235200, 1401321600,
1401408000, 1401494400, 1401580800, 1401667200, 1402272000,
1402358400, 1402444800, 1402531200, 1402617600, 1402704000,
1402790400, 1402876800), class = c("POSIXct", "POSIXt"), tzone = "UTC"),
rainfall = c(0.8, 0, 1.4, 3, 0, 1, 0, 0, 3, 0, 2.4, 1.2,
0, 0, 0, 0), temperature = c(23.6, 21.9, 22.6, 20.1, 21.9,
20.3, 17.3, 15.5, 23.1, 22.4, 21.1, 20.4, 21.2, 21.5, 20.2,
20.4)), row.names = c(NA, -16L), class = c("tbl_df", "tbl",
"data.frame"))
disease_df <- structure(list(week = structure(1:2, levels = c("1", "2"), class = "factor"),
disease_intensity = c(0.4, 0.3)), row.names = c(NA, -2L), class = c("tbl_df",
"tbl", "data.frame"))
combine_df <- left_join(weather_df, disease_df, by = "week")
Вот результат
Как вы можете видеть, 0,4 добавляется ко всем дням недели 1, а 0,3 добавляется ко всем дням недели 2. Я просто хочу, чтобы они были добавлены к последним дням обеих недель, оставляя при этом другие ячейки пустыми.





Существует множество методов соединения, которые вы можете использовать, но в этом случае проще просто улучшить критерии соединения. Я добавил два критерия: день недели и совокупное количество этого дня, поскольку ваш счетчик недель включает два одинаковых дня недели.
Оттуда работает обычное левое соединение.
library(tidyverse)
weather_augmented_tbl <- weather_df |>
group_by(week) |>
mutate(
wday=wday(date)
,n_wday=cumsum(if_else(wday==2,1,0))
)
disease_augmented_tbl <- disease_df |>
mutate(
wday=2
,n_wday=2
)
left_join(
weather_augmented_tbl
,disease_augmented_tbl
,by=join_by(
week,wday,n_wday
)
)
Даррен ниже предоставил более простое решение без необходимости дополнять таблицы.
Вы можете объединить disease_df и weather_df с «последним совпадением» и присоединить результат обратно к weather_df.
library(dplyr)
left_join(disease_df, weather_df, by = "week", multiple = "last") %>%
left_join(weather_df, .)
Другой вариант — создать столбец flag в weather_df, указывающий последний день каждой недели, а затем объединить его с disease_df.
weather_df %>%
mutate(flag = row_number() == which.max(date), .by = week) %>%
left_join(mutate(disease_df, flag = TRUE), by = join_by(week, flag)) %>%
select(-flag)
# # A tibble: 16 × 5
# week date rainfall temperature disease_intensity
# <fct> <dttm> <dbl> <dbl> <dbl>
# 1 1 2014-05-26 00:00:00 0.8 23.6 NA
# 2 1 2014-05-27 00:00:00 0 21.9 NA
# 3 1 2014-05-28 00:00:00 1.4 22.6 NA
# 4 1 2014-05-29 00:00:00 3 20.1 NA
# 5 1 2014-05-30 00:00:00 0 21.9 NA
# 6 1 2014-05-31 00:00:00 1 20.3 NA
# 7 1 2014-06-01 00:00:00 0 17.3 NA
# 8 1 2014-06-02 00:00:00 0 15.5 0.4
# 9 2 2014-06-09 00:00:00 3 23.1 NA
# 10 2 2014-06-10 00:00:00 0 22.4 NA
# 11 2 2014-06-11 00:00:00 2.4 21.1 NA
# 12 2 2014-06-12 00:00:00 1.2 20.4 NA
# 13 2 2014-06-13 00:00:00 0 21.2 NA
# 14 2 2014-06-14 00:00:00 0 21.5 NA
# 15 2 2014-06-15 00:00:00 0 20.2 NA
# 16 2 2014-06-16 00:00:00 0 20.4 0.3
хороший! более эффективный, чем мой
Ответ Даррена, к сожалению, мне не помог. Я получил все NA с опцией flag и получил ошибку с опцией multiple. В данных должен присутствовать Error in left_join(): ! Join columns in x`. ✖Проблема с multiple. Обратная трассировка: 1. ... %>% left_join(weather_dat_daily, .) 9. dplyr:::left_join.data.frame(...)`
@Ahsk Думаю, ты используешь устаревшую dplyr версию. Вы можете установить последнюю версию с помощью install.packages("dplyr") и повторить попытку.
В базе R мы можем объединить дважды
merge(weather_df,
merge(disease_df, aggregate(date ~ week, weather_df, max), by = "week"),
by= c("week", "date"), all.x = TRUE)
week date rainfall temperature disease_intensity
1 1 2014-05-26 0.8 23.6 NA
2 1 2014-05-27 0.0 21.9 NA
3 1 2014-05-28 1.4 22.6 NA
4 1 2014-05-29 3.0 20.1 NA
5 1 2014-05-30 0.0 21.9 NA
6 1 2014-05-31 1.0 20.3 NA
7 1 2014-06-01 0.0 17.3 NA
8 1 2014-06-02 0.0 15.5 0.4
9 2 2014-06-09 3.0 23.1 NA
10 2 2014-06-10 0.0 22.4 NA
11 2 2014-06-11 2.4 21.1 NA
12 2 2014-06-12 1.2 20.4 NA
13 2 2014-06-13 0.0 21.2 NA
14 2 2014-06-14 0.0 21.5 NA
15 2 2014-06-15 0.0 20.2 NA
16 2 2014-06-16 0.0 20.4 0.3
Уверен, это можно написать более кратко.
Просто добавьте даты max к заболеванию_df и merge.
> merge(weather_df,
+ transform(disease_df,
+ date=with(weather_df, tapply(date, week, max))),
+ all=TRUE)
week date rainfall temperature disease_intensity
1 1 2014-05-26 0.8 23.6 NA
2 1 2014-05-27 0.0 21.9 NA
3 1 2014-05-28 1.4 22.6 NA
4 1 2014-05-29 3.0 20.1 NA
5 1 2014-05-30 0.0 21.9 NA
6 1 2014-05-31 1.0 20.3 NA
7 1 2014-06-01 0.0 17.3 NA
8 1 2014-06-02 0.0 15.5 0.4
9 2 2014-06-09 3.0 23.1 NA
10 2 2014-06-10 0.0 22.4 NA
11 2 2014-06-11 2.4 21.1 NA
12 2 2014-06-12 1.2 20.4 NA
13 2 2014-06-13 0.0 21.2 NA
14 2 2014-06-14 0.0 21.5 NA
15 2 2014-06-15 0.0 20.2 NA
16 2 2014-06-16 0.0 20.4 0.3
Вариант решения @Darren Tsai с right_join:
library(tidyverse)
new_df <- arrange(right_join(disease_df , weather_df, by = "week", multiple = "last"), date)
Выход:
> new_df
# A tibble: 16 × 5
week disease_intensity date rainfall temperature
<fct> <dbl> <dttm> <dbl> <dbl>
1 1 NA 2014-05-26 00:00:00 0.8 23.6
2 1 NA 2014-05-27 00:00:00 0 21.9
3 1 NA 2014-05-28 00:00:00 1.4 22.6
4 1 NA 2014-05-29 00:00:00 3 20.1
5 1 NA 2014-05-30 00:00:00 0 21.9
6 1 NA 2014-05-31 00:00:00 1 20.3
7 1 NA 2014-06-01 00:00:00 0 17.3
8 1 0.4 2014-06-02 00:00:00 0 15.5
9 2 NA 2014-06-09 00:00:00 3 23.1
10 2 NA 2014-06-10 00:00:00 0 22.4
11 2 NA 2014-06-11 00:00:00 2.4 21.1
12 2 NA 2014-06-12 00:00:00 1.2 20.4
13 2 NA 2014-06-13 00:00:00 0 21.2
14 2 NA 2014-06-14 00:00:00 0 21.5
15 2 NA 2014-06-15 00:00:00 0 20.2
16 2 0.3 2014-06-16 00:00:00 0 20.4
Подойдет только right_join, но не по порядку (т. е. в порядке disease_df), следовательно, arrange. disease_intensity будет вторым столбцом (как в disease_df).
Редактировать
..и однострочник base-r:
# weather_df$new <- NA_real_ --> Avoid the "unknown or uninitialised colum" warning
weather_df$disease_intensity[cumsum(rle(as.numeric(weather_df$week))$lengths)] <- disease_df$disease_intensity
cumsum(rle(...)$lengths указывает позицию последнего последовательно повторяющегося элемента в векторе.
as.numeric(...) необходим только потому, что weather_df$week — это factor.
Тот же вывод:
> weather_df
# A tibble: 16 × 5
week date rainfall temperature disease_intensity
<fct> <dttm> <dbl> <dbl> <dbl>
1 1 2014-05-26 00:00:00 0.8 23.6 NA
2 1 2014-05-27 00:00:00 0 21.9 NA
3 1 2014-05-28 00:00:00 1.4 22.6 NA
4 1 2014-05-29 00:00:00 3 20.1 NA
5 1 2014-05-30 00:00:00 0 21.9 NA
6 1 2014-05-31 00:00:00 1 20.3 NA
7 1 2014-06-01 00:00:00 0 17.3 NA
8 1 2014-06-02 00:00:00 0 15.5 0.4
9 2 2014-06-09 00:00:00 3 23.1 NA
10 2 2014-06-10 00:00:00 0 22.4 NA
11 2 2014-06-11 00:00:00 2.4 21.1 NA
12 2 2014-06-12 00:00:00 1.2 20.4 NA
13 2 2014-06-13 00:00:00 0 21.2 NA
14 2 2014-06-14 00:00:00 0 21.5 NA
15 2 2014-06-15 00:00:00 0 20.2 NA
16 2 2014-06-16 00:00:00 0 20.4 0.3
Спасибо. Это работает, но есть ли способ автоматически выбрать последнюю строку недели? У меня есть другой набор данных, в котором данные о погоде записываются с ежечасными интервалами, поэтому для одной даты есть много строк. Заболевание регистрировалось в разное время суток, поэтому определить состояние сложно.