Я прокомментировал, что вам нужен лучший подход к этой проблеме.
Я предлагаю вам рассмотреть это с точки зрения структурированной базы данных . С этой точки зрения, ваши данные (и, следовательно, ваш мир) состоят из таблиц с различной и дополнительной информацией. И когда вам нужно получить информацию для решения вашей проблемы, вы объединяете данные из разных таблиц. Если вы использовали Excel, то вы будете знать это как vlookup
.
Как бы я подошел к вашей проблеме:
Таблица компонентов:
Сначала у меня будет таблица компонентов. Это будет очень простая таблица из 3 столбцов: name
продукта, component
, из которого оно изготовлено, и amount
необходимого компонента.
Для вашего примера у меня будет
library(data.table)
components <- structure(list(name = c("a", "b", "a_bund", "a_bund", "b_bund"),
component = c("a", "b", "a", "b", "b"),
amount = c(1, 1, 1, 1, 2)),
row.names = c(NA, -5L),
class = c("data.table", "data.frame"))
Который будет производить:
components
name component amount
1: a a 1
2: b b 1
3: a_bund a 1
4: a_bund b 1
5: b_bund b 2
Обратите внимание, что информация, содержащаяся здесь, - это та же информация, что и ваша таблица в столбцах 4-7 (кстати, ваша таблица называется «широкая», а моя - «длинной»). Long намного лучше для машинной обработки, и это считается "аккуратным").
Таблица запросов
Теперь, когда у вас есть таблица для компонентов, вам понадобится таблица, чтобы указать, сколько единиц продукта x нужно вашим клиентам к y дате. Вы заметили, что я разделил информационное содержание в обеих таблицах? Там один с компонентами и ничего больше; и есть один с запросами и больше ничего. Каждая вещь в своей корзине!
Эту таблицу я назвал requests
, и она состоит из трех столбцов: dates
с датой запроса, name
с названием запрошенного клиентом продукта и qty
с количеством клиента ожидает от продукта. Это будет то, что у вас есть в столбцах с 1 по 3 в ваших данных.
requests <- structure(list(dates = structure(c(17902, 17902, 17902, 17903, 17903, 17903), class = "Date"),
name = c("a_bund", "a", "b", "b_bund", "b_bund", "b"),
qty = c(1, 1, 2, 1, 2, 2)),
row.names = c(NA, -6L),
class = c("data.table", "data.frame"))
Который производит:
requests
dates name qty
1: 2019-01-06 a_bund 1
2: 2019-01-06 a 1
3: 2019-01-06 b 2
4: 2019-01-07 b_bund 1
5: 2019-01-07 b_bund 2
6: 2019-01-07 b 2
Присоединение к столам
С этими двумя таблицами теперь вам нужно знать, сколько каждого компонента вам понадобится в любой конкретный день. Для решения этой проблемы я буду использовать пакет data.table, подробности см. ?data.table
.
requests[components, on = "name" ][, sum(qty*amount), by = .(dates, component)]
Что там?
requests[components, on = "name"]
объединяет таблицу requests
с components
, сопоставляя элементы с одинаковым name
. Другими словами, он приносит component
и amount
(из компонентов, конечно) для каждого name
в requests
. Вставьте команду и посмотрите, каков будет результат.
Синтаксис Data.table позволяет «связывать» в цепочку или передавать промежуточный результат в новую операцию. Вот что происходит с последовательностью ][
: я присоединился к таблицам и теперь передаю этот результат в новую операцию.
Эта новая операция sum(qty * amount)
. Он умножает (изначально вы не ошиблись) количество запрашиваемых юнитов qty
на количество каждого component
, необходимого для его производства, и суммирует (агрегирует) by = .(dates, component)
, что кажется довольно очевидным. (Если вы из мира Excel, просто подумайте о сводной или динамической таблице).
Это дает ожидаемый результат:
requests[components, on = "name" ][, sum(qty*amount), by = .(dates, component)]
dates component V1
1: 2019-01-06 a 2
2: 2019-01-06 b 3
3: 2019-01-07 b 8
Несмотря на то, что в результате получаются те же самые ответы, которые уже были предоставлены, я надеюсь, что вы видите разницу в подходах и улучшенное удобство использования этого. Если нет, просто представьте, что k_bundle
состоит из 19 различных компонентов ;)