Объединить 2 набора данных в длинном формате на основе условия - PullRequest
1 голос
/ 11 апреля 2020

У меня есть 2 фрейма данных, которые я хотел бы объединить. Разница между наборами данных заключается в количестве наблюдений и способе их сбора. В df1 наблюдения были зафиксированы в 2 разных дня. Каждая запись имеет индекс, идентификационный номер человека id1, а id2 обозначает номер дня, когда была сделана запись (день должен был быть другим). Также существует переменная Day, которая записывает день недели, когда была сделана запись.

В df2 наблюдения были записаны только на основе серийного номера и идентификационного номера человека id1. На человека приходится только одно наблюдение. Точно так же здесь есть также переменная Day, которая записывает время начала записи.

Я хотел бы идентифицировать наблюдения из df2, которые были записаны в тот же день, что и в df1.

Я попытался создать новый индекс (для индекса группы и id1) для go для long и объединить по дням.

Df1: - day обозначает время, когда были сделаны наблюдения (например, индекс 12; id1 - обозначает только 1 человека; id2 обозначает 2 дня - среда id2 1 и воскресенье id2 2)

    index id1 id2  Day         obs1 obs2 obs3
     12    1   1   Wednesday    1    11   12
     12    1   2   Sunday       2     0    0
    123    1   1   Tuesday      1     0    1
    123    1   2   Saturday     3     0    3
    123    2   1   Monday       2     2    4
    123    2   2   Saturday     1     0    8

df2: - здесь переменная дня Day обозначает начальный день, с которого наблюдения были сделано (например, идентификатор 12 дня2 и идентификатор 123 дня1)

index   id1  Day       day1 day2 day3 day4 day5 day6  day7   
 12      1    Tuesday     2    1    2    1    1    3    1    
123      1    Friday      0    3    0    3    3    0    3     

Результат:

 index id1 id2   obs1 obs2 obs3 
 12      1   1     1   11    12   
 12      1   2     2    0     0
 123     1   2     3    0     3        
 123     2   2     1    0     8

Пример данных

df1:

structure(list(index = c(12, 12, 123, 123, 123, 123), id1 = c(1, 
1, 1, 1, 2, 2), id2 = c(1, 2, 1, 2, 1, 2), Day = structure(c(5L, 
3L, 4L, 2L, 1L, 2L), .Label = c("Monday", "Saturday", "Sunday", 
"Tuesday", "Wednesday"), class = "factor"), obs1 = c(1, 2, 1, 
3, 2, 1), obs2 = c(11, 0, 0, 0, 2, 0), obs3 = c(12, 0, 1, 3, 
4, 8)), class = "data.frame", row.names = c(NA, -6L))

df2:

structure(list(index = c(12, 123), id1 = c(1, 1), Day = structure(2:1, .Label = c("Friday", 
"Tuesday"), class = "factor"), day1 = c(2, 0), day2 = c(1, 3), 
    day3 = c(2, 0), day4 = c(1, 3), day5 = c(1, 3), day6 = c(3, 
    0), day7 = c(1, 3)), class = "data.frame", row.names = c(NA, 
-2L))

Ответы [ 2 ]

1 голос
/ 11 апреля 2020

Опция с melt из data.table

library(data.table)
weekday <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")

Если наборы данных haven labelled 'Day', мы сначала конвертируем в factor с as_factor

library(haven)
df1$Day <- as.character(as_factor(df1$Day))
df2$Day <- as.character(as_factor(df2$Day))
df1$Day <- match(df1$Day, weekday) 
dt2 <- melt(setDT(df2), measure = patterns('^day\\d+$'))[seq_len(.N) >=
    match(Day, weekday)[1L]][, .(Day = match(Day, weekday)[1]), index]
merge(setDT(df1), dt2, by = 'index')[Day.y < Day.x]
#   index id1 id2 Day.x obs1 obs2 obs3 Day.y
#1:    12   1   1     3    1   11   12     2
#2:    12   1   2     7    2    0    0     2
#3:   123   1   2     6    3    0    3     5
#4:   123   2   2     6    1    0    8     5

Или, используя tidyverse, лучше вернуть list столбец в summarise, а затем unnest (если длины не совпадают с количеством строк)

library(dplyr)
library(tidyr)
df2 %>%
     pivot_longer(cols = day1:day7) %>%
     group_by(index) %>% 
     slice(match(Day, weekday)[1L]:n()) %>%
     summarise(Day = match(Day, weekday)[1]) %>%
     inner_join(df1 %>%
     mutate(Day = match(Day, weekday)), by = 'index') %>%
     filter(Day.y >= Day.x)
# A tibble: 4 x 8
#  index Day.x   id1   id2 Day.y  obs1  obs2  obs3
#  <dbl> <int> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
#1    12     2     1     1     3     1    11    12
#2    12     2     1     2     7     2     0     0
#3   123     5     1     2     6     3     0     3
#4   123     5     2     2     6     1     0     8
1 голос
/ 11 апреля 2020

Мы можем получить формат df2 lin long, group_by index сохранить строки, которые произошли после выполнения наблюдений, и объединить их с df1 на основе index и Day.

library(dplyr)
weekday <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", 
             "Saturday", "Sunday")


df2 %>%
  mutate_at(vars(matches('day\\d+')), as.numeric) %>%
  tidyr::pivot_longer(cols = matches('day\\d+')) %>%
  group_by(index) %>%
  filter(row_number() >= match(Day, weekday)[1L]) %>%
  summarise(Day = match(Day, weekday)[1]) %>%
  inner_join(df1 %>%mutate(Day = match(Day, weekday)), by = 'index') %>%
  filter(Day.y >= Day.x)


#  index Day.x   id1   id2 Day.y  obs1  obs2  obs3
#  <dbl> <int> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
#1    12     2     1     1     3     1    11    12
#2    12     2     1     2     7     2     0     0
#3   123     5     1     2     6     3     0     3
#4   123     5     2     2     6     1     0     8

Затем вы можете использовать select, чтобы сохранить только те столбцы, которые необходимы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...