Объединение информационных кадров с различными размерами и заполнение пробелов - PullRequest
1 голос
/ 07 октября 2019

Я хочу объединить два разных кадра данных. Эти кадры данных имеют разные размеры. Вот примеры наборов данных,

Основной набор данных

# Main data
id <- c(rep(1, 3), rep(3, 3), rep(10, 1))
time <- c(201601, 201602, 201603, 201601, 201602, 201603, 201601)
data1 <- c(100, 150, 160, 111, 120, 130, 150)
data2 <- c(5, 6, 9, 3, 2, 1, 0)
dataf1 <- data.frame(id, time, data1, data2) 

Кадр данных для объединения с основным набором данных

# Additional data
id <- c(3, 10, 2)
time <- c(rep(201604, 3))
data2 <- c(20, 30, 11)
dataf2 <- data.frame(id, time, data2)

Я хочу объединить эти два кадра данных, а именно dataf1 и dataf2. Я пытался dplyr::full_join(dataf1, dataf2, by = "id"), но он не дает то, что я хочу. Ожидаемое соединение должно выглядеть следующим образом:

enter image description here

Однако окончательный вывод должен включать отсутствующие временные метки. Окончательный результат должен выглядеть следующим образом:

enter image description here

Есть ли способ, которым я могу достичь этого?

Ответы [ 3 ]

2 голосов
/ 07 октября 2019

Вот таблица data.table на ваш вопрос

library(data.table)
#create data.tables out of your data.frames
setDT(dataf1)
setDT(dataf2)

#row-bind all your data together
alldata <- rbindlist( list( dataf1, dataf2 ), use.names = TRUE, fill = TRUE )
#get all unique id-time combinations out of your data
DT <- CJ( alldata$id, alldata$time, unique = TRUE)
setnames(DT, names(DT), c("id", "time"))
#join your data to all unique combinataions of id-time
ans <- DT[ alldata, `:=`( data1 = i.data1, data2 = i.data2), on = .(id, time)]

weput

#    id   time data1 data2
# 1:  1 201601   100     5
# 2:  1 201602   150     6
# 3:  1 201603   160     9
# 4:  1 201604    NA    NA
# 5:  2 201601    NA    NA
# 6:  2 201602    NA    NA
# 7:  2 201603    NA    NA
# 8:  2 201604    NA    11
# 9:  3 201601   111     3
# 10: 3 201602   120     2
# 11: 3 201603   130     1
# 12: 3 201604    NA    20
# 13:10 201601   150     0
# 14:10 201602    NA    NA
# 15:10 201603    NA    NA
# 16:10 201604    NA    30

Как вы видите, он (почти) соответствует вашему желаниювывод.
Я запутался, почему вы хотели, чтобы id = 10 & time = 201604 ==> data1 = 30. Почему это поведение, хотя data1 = NA и data2 = 30?

Конечно, вы можетелегко обмениваться данными1 с данными2, используя ifelse -подобное решение в виде ans[ is.na(data1) & !is.na(data2),: = (data1 = data2, data2 = NA)]

1 голос
/ 07 октября 2019

Это соответствует вашему точному окончательному результату :

library(data.table)
setnames(dataf2, "data2", "data1") # Warning: This will modify the original dataf2
rbindlist(
  list(dataf1, dataf2), 
  fill = TRUE
)[CJ(id, time, unique = TRUE), on = .(id, time)]

#     id   time data1 data2
#  1:  1 201601   100     5
#  2:  1 201602   150     6
#  3:  1 201603   160     9
#  4:  1 201604    NA    NA
#  5:  2 201601    NA    NA
#  6:  2 201602    NA    NA
#  7:  2 201603    NA    NA
#  8:  2 201604    11    NA
#  9:  3 201601   111     3
# 10:  3 201602   120     2
# 11:  3 201603   130     1
# 12:  3 201604    20    NA
# 13: 10 201601   150     0
# 14: 10 201602    NA    NA
# 15: 10 201603    NA    NA
# 16: 10 201604    30    NA
1 голос
/ 07 октября 2019

Вот один из способов использования tidyr::complete с dplyr. После выполнения full_join мы конвертируем столбец time в объект Date. Для каждой id complete последовательности от минимального значения до '2016-04-01' и удаления NA строк.

library(dplyr)

full_join(dataf1, dataf2, by = "id") %>%
   select(-time.y, -data2.y) %>%
   rename_all(~names(dataf1)) %>%
   mutate(time1 = as.Date(paste0(time, "01"), "%Y%m%d")) %>%
   tidyr::complete(id, time1 = seq(min(time1, na.rm = TRUE), 
                   as.Date('2016-04-01'), by = "1 month")) %>%
   mutate(time = format(time1, "%Y%m")) %>%
   filter_at(vars(-id), any_vars(!is.na(.))) %>%
   select(-time1)


#      id time   data1 data2
#    <dbl> <chr>  <dbl> <dbl>
# 1     1 201601   100     5
# 2     1 201602   150     6
# 3     1 201603   160     9
# 4     1 201604    NA    NA
# 5     2 201601    NA    NA
# 6     2 201602    NA    NA
# 7     2 201603    NA    NA
# 8     2 201604    NA    NA
# 9     3 201601   111     3
#10     3 201602   120     2
#11     3 201603   130     1
#12     3 201604    NA    NA
#13    10 201601   150     0
#14    10 201602    NA    NA
#15    10 201603    NA    NA
#16    10 201604    NA    NA
...