Соедините два фрейма данных, используя последнюю строку из каждой группы

Наша метеостанция записывала ежедневные данные о погоде (около 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. Я просто хочу, чтобы они были добавлены к последним дням обеих недель, оставляя при этом другие ячейки пустыми.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
119
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

Существует множество методов соединения, которые вы можете использовать, но в этом случае проще просто улучшить критерии соединения. Я добавил два критерия: день недели и совокупное количество этого дня, поскольку ваш счетчик недель включает два одинаковых дня недели.

Оттуда работает обычное левое соединение.

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
  )
)

Спасибо. Это работает, но есть ли способ автоматически выбрать последнюю строку недели? У меня есть другой набор данных, в котором данные о погоде записываются с ежечасными интервалами, поэтому для одной даты есть много строк. Заболевание регистрировалось в разное время суток, поэтому определить состояние сложно.

Ahsk 20.05.2024 04:14

Даррен ниже предоставил более простое решение без необходимости дополнять таблицы.

alejandro_hagan 20.05.2024 04:24

Вы можете объединить 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

хороший! более эффективный, чем мой

alejandro_hagan 20.05.2024 04:24

Ответ Даррена, к сожалению, мне не помог. Я получил все 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 20.05.2024 04:54

@Ahsk Думаю, ты используешь устаревшую dplyr версию. Вы можете установить последнюю версию с помощью install.packages("dplyr") и повторить попытку.

Darren Tsai 20.05.2024 04:59

В базе 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

Другие вопросы по теме