R: найдите и добавьте отсутствующие (/не существующие) строки во временном фрейме данных

Я борюсь со следующим.

Если у вас есть (большой) кадр данных со следующим:

  • несколько столбцов, для которых комбинация столбцов является "уникальной" комбинацией, например идентификатор
  • связанный со временем столбец
  • связанный с измерением столбец

Я хочу убедиться, что для каждого уникального идентификатора для каждого временного интервала в кадре данных доступна мера. И если это не так, я хочу добавить меру 0 (или NA) для этого времени /ID.

Чтобы проиллюстрировать проблему, создайте следующий кадр данных test:

test <- data.frame(
    YearWeek   =rep(c("2012-01","2012-02"),each=4),
    ProductID  =rep(c(1,2), times=4),
    CustomerID =rep(c("a","b"), each=2, times=2),
    Quantity   =5:12
)[1:7,]

  YearWeek ProductID CustomerID Quantity
1  2012-01         1          a        5
2  2012-01         2          a        6
3  2012-01         1          b        7
4  2012-01         2          b        8
5  2012-02         1          a        9
6  2012-02         2          a       10
7  2012-02         1          b       11

8-я строка не используется специально. Таким образом, я имитирую "недостающее значение" (отсутствует Quantity) для идентификатора "2-b" (ProductID-CustomerID) для значения времени "2012-02".

Что я хочу сделать, так это отредактировать data.frame таким образом, чтобы для всех значений времени (они известны в этом примере только "2012-01" и "2012-02" ), для всех ID-комбинаций (они неизвестны заранее, но это "все уникальные комбинации идентификаторов в кадре данных", таким образом, уникальный набор в столбцах идентификатора), количество доступно в кадре данных.

Это должно привести к этому примеру (если мы выберем NA для отсутствующего значения, обычно я хочу иметь контроль над этим):

  YearWeek ProductID CustomerID Quantity
1  2012-01         1          a        5
2  2012-01         2          a        6
3  2012-01         1          b        7
4  2012-01         2          b        8
5  2012-02         1          a        9
6  2012-02         2          a       10
7  2012-02         1          b       11
8  2012-02         2          b       NA

Конечная цель - создать временные ряды для этих комбинаций идентификаторов, и поэтому я хочу иметь количество для всех значений времени. Мне нужно выполнить различные агрегации (по времени) и использовать разные уровни идентификатора из большого набора данных

Я попробовал несколько вещей, например melt и cast из пакета reshape. Но пока мне это не удалось. Следующим шагом является создание функции с помощью for-loops и т.д., Но это не очень полезно с точки зрения производительности.

Возможно, есть более простой способ мгновенного создания временных рядов, дающий data.frame как test. У кого-нибудь есть идея об этом?

Спасибо заранее!

Обратите внимание, что в реальной задаче имеется более двух "столбцов идентификаторов".


EDIT:

Я должен описать проблему дальше. Существует разница между столбцом "время" и столбцами "ID". Первый (и большой!) Ответ на вопрос joran, возможно, не получил ясного понимания из того, что я хочу (и пример, который я дал, не сделал разницы ясными). Я сказал выше:

для всех ID-комбинаций (они не известны заранее, но это все уникальные комбинации идентификаторов в кадре данных ", таким образом, уникальный набор на Идентификаторы)

Поэтому мне не нужны "все возможные комбинации идентификаторов", но "все идентификационные комбинации в данных". Для каждой из этих комбинаций я хочу значение для каждого уникального значения времени.

Позвольте мне пояснить, расширяя test до test2 следующим образом

> test2 <- rbind(test, c("2012-02", 3, "a", 13))
> test2
  YearWeek ProductID CustomerID Quantity
1  2012-01         1          a        5
2  2012-01         2          a        6
3  2012-01         1          b        7
4  2012-01         2          b        8
5  2012-02         1          a        9
6  2012-02         2          a       10
7  2012-02         1          b       11
8  2012-02         3          a       13

Это означает, что я хочу, чтобы в результирующем фрейме данных не было идентификатора "3-b", потому что эта комбинация не находится в пределах test2. Если я использую метод первого ответа, я получу следующее:

> vals2 <- expand.grid(YearWeek = unique(test2$YearWeek),
                       ProductID = unique(test2$ProductID),
                       CustomerID = unique(test2$CustomerID))

> merge(vals2,test2,all = TRUE)
   YearWeek ProductID CustomerID Quantity
1   2012-01         1          a        5
2   2012-01         1          b        7
3   2012-01         2          a        6
4   2012-01         2          b        8
5   2012-01         3          a     <NA>
6   2012-01         3          b     <NA>
7   2012-02         1          a        9
8   2012-02         1          b       11
9   2012-02         2          a       10
10  2012-02         2          b     <NA>
11  2012-02         3          a       13
12  2012-02         3          b     <NA>

Поэтому я не хочу, чтобы строки 6 и 12 были здесь.

Чтобы преодолеть эту проблему, я нашел решение в приведенном ниже. Здесь я разделяю "уникальный столбец времени" и "уникальную комбинацию идентификаторов". Таким образом, разница с выше - это слово "комбинация", а не уникальное для каждого столбца идентификатора.

> temp_merge <- merge(unique(test2["YearWeek"]),
                      unique(test2[c("ProductID", "CustomerID")]))

> merge(temp_merge,test2,all = TRUE)
   YearWeek ProductID CustomerID Quantity
1   2012-01         1          a        5
2   2012-01         1          b        7
3   2012-01         2          a        6
4   2012-01         2          b        8
5   2012-01         3          a     <NA>
6   2012-02         1          a        9
7   2012-02         1          b       11
8   2012-02         2          a       10
9   2012-02         2          b     <NA>
10  2012-02         3          a       13

Каковы комментарии к этому?

Это элегантный способ, или есть ли лучшие способы?

Ответы

Ответ 1

Используйте expand.grid и merge:

vals <- expand.grid(YearWeek = unique(test$YearWeek),
                    ProductID = unique(test$ProductID),
                    CustomerID = unique(test$CustomerID))
> merge(vals,test,all = TRUE)
  YearWeek ProductID CustomerID Quantity
1  2012-01         1          a        5
2  2012-01         1          b        7
3  2012-01         2          a        6
4  2012-01         2          b        8
5  2012-02         1          a        9
6  2012-02         1          b       11
7  2012-02         2          a       10
8  2012-02         2          b       NA

NA можно заменить после факта с любыми значениями, которые вы выбираете, используя подмножество и is.na.