R: Вставить отсутствующие даты в продольные данные без потери информации

У меня есть продольный набор данных в таблице данных, аналогичный приведенному ниже упрощенному примеру:

> head(data)
   Country     ID        Date         Value
1:   AT        AT6306    2012-11-01   16.2
2:   AT        AT6306    2012-11-02   12.2
3:   AT        AT6306    2012-11-03   11.3
4:   AT        AT6306    2012-11-04   14.2
5:   AT        AT6306    2012-11-05   17.3
6:   AT        AT6306    2012-11-06   12.5

> tail(data)
   Country     ID        Date         Value
1:   SE        SE0935    2014-06-25   16.2
2:   SE        SE0935    2014-06-26   12.2
3:   SE        SE0935    2014-06-27   11.3
4:   SE        SE0935    2014-06-28   14.2
5:   SE        SE0935    2014-06-29   17.3
6:   SE        SE0935    2014-06-30   12.5

ID — переменная панели, она полностью уникальна и не пересекается между странами. Диапазон дат, учитывающий только уникальные значения, находится в диапазоне от 2012-10-23 до 2014-09-30. Ясно, что диапазоны Date не идентичны для каждого ID. Кроме того, могут быть пропущенные значения. Чтобы получить сбалансированную панель, я хочу заполнить пробелы в своем наборе данных.

Адаптация ответа здесь , как предложил @akron, я делаю следующее:

data2 <- data[, CJ(ID=unique(ID), Date=unique(Date))]
setkey(data2, ID, Date)

data.new <- merge(data, data2, by=c("ID", "Date"), all.y = TRUE)
setkey(data.new, ID, Date)

Таким образом, используя параметр all.y = TRUE, R добавляет строки для каждой отсутствующей даты в data. Однако теперь все поля, кроме ID и Date, пусты, если строки в data ранее не существовало. То есть мои данные выглядят примерно так

> head(data.new)
   Country     ID        Date         Value
1:   NA        AT6306    2012-10-23   NA
2:   NA        AT6306    2012-10-24   NA
3:   NA        AT6306    2012-10-25   NA
4:   NA        AT6306    2012-10-26   NA
5:   NA        AT6306    2012-10-27   NA
6:   NA        AT6306    2012-10-28   NA    

Я хочу, чтобы Value было NA, так как оно отсутствует. Однако, поскольку Country не меняется для данного ID, я бы хотел, чтобы поле было заполнено.


person altabq    schedule 03.11.2014    source источник
comment
В этих странах одинаковый диапазон дат?   -  person akrun    schedule 03.11.2014
comment
Да, диапазон от 01.11.2011 до 30.06.2014. Я обновлю вопрос, чтобы включить этот факт   -  person altabq    schedule 03.11.2014
comment
Взгляните на этот ответ от eddi.   -  person Arun    schedule 03.11.2014
comment
Итак, первая команда создает новую таблицу данных с использованием последовательности для создания диапазона дат без пропусков, вторая назначает ключи (таким образом, она также сортирует таблицу данных), а третья должна отображать значения во вновь созданном фрейме, правильно? У меня все работает до последней команды, где я получаю ошибку: Error in bmerge(i <- shallow(i), x, leftcols, rightcols, io <- haskey(i), : typeof x.Date (double) != typeof i.ID (integer)   -  person altabq    schedule 03.11.2014
comment
Я должен был отметить, что идентификатор на самом деле является фактором, который может содержать буквы и цифры.   -  person altabq    schedule 03.11.2014
comment
@akrun, я не понимаю, как вы пришли к своему ответу по ссылке, которую я предоставил. Он использует CJ() в i простым способом, после установки ключей на DT. Зачем использовать его в j...?!?   -  person Arun    schedule 03.11.2014
comment
@altabq, этот вопрос очень похож на дубликат того, на который я ссылался. Прочтите ?CJ и посмотрите, как используется этот пост. Это прямое соединение. Установите ключи с data на Country, ID, Date. И используйте DT[CJ(...)] - это заполнит все пропущенные значения NA по умолчанию.   -  person Arun    schedule 03.11.2014
comment
@altabq, предоставьте воспроизводимые данные (код, который мы можем скопировать/вставить). Акрон, какой код, который вы пробовали, дал неверный результат? Из того, что я вижу, ваш и окольный путь достижения DT[CJ(...)].   -  person Arun    schedule 03.11.2014
comment
@akrun Вы правы, ответ почти такой же. Мне удалось создать новую таблицу с помощью слияния. У меня есть одна небольшая проблема. У меня есть еще пара полей, которые задают атрибуты сущностям. Таким образом, для каждого идентификатора есть имя объекта и некоторые другие вещи. Есть ли способ добавить это в DT2 с помощью CJ?   -  person altabq    schedule 03.11.2014
comment
@altabq Было бы лучше, если бы вы предоставили вывод dput. т.е. dput(head(data,20)) . В созданном мной примере Country — это класс символов.   -  person akrun    schedule 03.11.2014
comment
@akrun, я бы очень хотел это сделать, но данные являются собственностью. Поэтому я не могу привести конкретный пример. По сути, для каждого идентификатора у меня есть несколько столбцов класса факторов, каждая строка уникальна для идентификатора. В контексте Country, который для меня является классом факторов: я использую data.new <- merge(data2, data, by=c("ID", "Date"), all.x = TRUE) для сопоставления двух наборов данных. Однако тогда Страна будет NA для дат, которые ранее не существовали в поле dData. Is it possible to add the Country` уже в таблице данных data2? data2 <- data[, CJ(ID=unique(ID), Date=unique(Date)]   -  person altabq    schedule 03.11.2014
comment
@akrun, да пожалуйста. По сути, моя проблема заключается в том, что при объединении с параметром all.x = TRUE новые строки добавляются для значений, которые существуют в data2 (таблица данных без пробелов), но не в data (исходная таблица данных, которая может содержать пробелы). Поскольку data2 определяется через data2 <- data[, CJ(ID=unique(ID), Date=unique(Date)], он не имеет значений для других атрибутов каждой сущности (например, Country). Следовательно, поле содержит. Я думаю, вы сможете воспроизвести это, оставив одну страну пустой в таблице данных data.   -  person altabq    schedule 03.11.2014
comment
@altabq Если вы проверите вывод, который я опубликовал, вы увидите, что поле «Страна» есть.   -  person akrun    schedule 03.11.2014
comment
@altabq Я обновил пост. Пожалуйста, проверьте, работает ли это для вас.   -  person akrun    schedule 03.11.2014
comment
@akrun, это работает, да! Большое спасибо за всю вашу помощь и время с этим!   -  person altabq    schedule 03.11.2014


Ответы (1)


library(data.table)
DT <- data.table(dat)
setkey(DT, Date, Country, ID)
res <- DT[CJ(seq(min(Date), max(Date), by='1 day'), 
                        unique(Country), unique(ID))]

 head(res)
#    Country   ID       Date Value
#1:      AT  935 2012-11-01    NA
#2:      AT 6306 2012-11-01  16.2
#3:      SE  935 2012-11-01    NA
#4:      SE 6306 2012-11-01    NA
#5:      AT  935 2012-11-02    NA
#6:      AT 6306 2012-11-02  12.2

Обновлять

Один из вариантов, который вы могли бы сделать, это

DT <- data.table(dat)
DT[,CountryID:= paste(Country,ID)]
setkey(DT, Date, CountryID)
DT1 <- DT[CJ(unique(Date), unique(CountryID))][,
      c('Country', 'ID'):=  list(gsub("[ 0-9]", "", CountryID),
               gsub("[^ 0-9]", "", CountryID)),][,-5L]


head(DT1,3)
#     Country    ID       Date Value
#1:      AT  6306 2012-11-01  16.2
#2:      SE   935 2012-11-01    NA
#3:      AT  6306 2012-11-02  12.2

nrow(DT1)
#[1] 24

данные

dat <- structure(list(Country = c("AT", "AT", "AT", "AT", "AT", "AT", 
"SE", "SE", "SE", "SE", "SE", "SE"), ID = c(6306L, 6306L, 6306L, 
6306L, 6306L, 6306L, 935L, 935L, 935L, 935L, 935L, 935L), Date = structure(c(15645, 
15646, 15647, 15648, 15649, 15650, 15669, 15670, 15671, 15672, 
15673, 15674), class = "Date"), Value = c(16.2, 12.2, 11.3, 14.2, 
17.3, 12.5, 16.2, 12.2, 11.3, 14.2, 17.3, 12.5)), .Names = c("Country", 
"ID", "Date", "Value"), row.names = c("1:", "2:", "3:", "4:", 
"5:", "6:", "1:1", "2:1", "3:1", "4:1", "5:1", "6:1"), class = "data.frame")
person akrun    schedule 03.11.2014
comment
Благодарю вас! Проблема, которая у меня есть, например. страна заключается в том, что я не добавляю ее в DT как unique, так как ID уже уникальна для разных стран. Итак, я использую только data2 <- data[, CJ(ID=unique(ID), Date=unique(Date)]. Но затем я получаю NA для стран. Если я добавлю Country=unique(Country), матрица станет намного больше, чем необходимо, поскольку тогда длина будет unique(Date)*unique(ID)*unique(Country) вместо unique(Date)*unique(ID), что является предполагаемым размером. - person altabq; 03.11.2014
comment
@altabq Основываясь на вашем коде, я получаю 24 строки и с NAs в Country. Итак, вы хотите изменить NA или удалить строки из кода, чтобы получить 24 строки? - person akrun; 03.11.2014
comment
Я хотел бы изменить NAs, чтобы там было соответствующее Country. Можно ли добавить, например. неуникальные поля уже в таблицу CJ? - person altabq; 03.11.2014
comment
@altabq Эти IDs уникальны для каждого Country или есть совпадения? - person akrun; 03.11.2014
comment
все IDs уникальны. Я должен был выбрать лучший пример, чем в моем вопросе, поскольку они больше похожи на AT6306 и SE0935. Таким образом, Country для слияния не требуется, но информацию следует сохранить. - person altabq; 03.11.2014
comment
Я перепишу свой вопрос на тот, к которому он в основном сводится сейчас. - person altabq; 03.11.2014