#r #dplyr #data.table #tidyr
#r #dplyr #данные.таблица #порядок
Вопрос:
У меня есть 2 таблицы данных, которые я хотел бы объединить, связав строки. Выходные данные dput приведены ниже:
>dput(x)
structure(list(NN = c("test", "test", "test", "test", "test"),
gpn = c("gas", "gas", "gas", "gas", "gas"), sitename = c("agip",
"agip", "agip", "agip", "agip"), code = c("F123", "F123",
"F123", "F123", "F123"), Brand = c("bp", "shell", "ionic",
"meta", "robo"), starttime = structure(c(1533097609, 1533118867,
1533183999, 1533270359, 1533356437), class = c("POSIXct",
"POSIXt"), tzone = ""), endtime = structure(c(1533118867,
1533183999, 1533270359, 1533356437, 1533443068), class = c("POSIXct",
"POSIXt"), tzone = ""), price = c(1.592, 1.592, 1.598, 1.598,
1.598), otherprice = c(1.998, 2.11, 2.114, 2.134, 1.989)), .Names = c("NN",
"gpn", "sitename", "code", "Brand", "starttime", "endtime", "price",
"otherprice"), row.names = c(NA, -5L), class = c("data.table",
"data.frame"), .internal.selfref = <pointer: 0x00000000025c0788>)
>dput(y)
structure(list(NN = c("test", "test", "test", "test", "test"),
gpn = c("gas", "gas", "gas", "gas", "gas"), sitename = c("agip",
"agip", "agip", "agip", "agip"), code = c("F123", "F123",
"F123", "F123", "F123"), Brand = c("dino", "dino", "dino",
"dino", "dino"), otherprice = c(1.987, 2.456, 3.456, 1.989,
1.99), starttime = structure(c(1533097399, 1533118999, 1533184999,
1533271999, 1533359357), tzone = "", class = c("POSIXct",
"POSIXt")), endtime = structure(c(1533118100, 1533182999,
1533270000, 1533356000, 1533443000), class = c("POSIXct",
"POSIXt"), tzone = "")), .Names = c("NN", "gpn", "sitename",
«код», «Бренд», «другая цена», «время начала», «время окончания»), class = c(«data.table»,
«data.frame»), .internal.selfref = )
Я хотел бы привязать строки от y до x таким образом, чтобы соответствовало следующее:
псевдокод:
If(NN, код из ‘x’ совпадает с NN, кодом из ‘y’) amp; ‘x $starttime’ < ‘y $ starttime’ amp; ‘x $endtime’ > ‘y$endtime’
Затем получите NN, код, марку, цену из ‘y’, и результирующий фрейм станет:
NN gpn sitename code Brand starttime endtime price otherprice
test gas agip F123 bp 01/08/2018 05:26 01/08/2018 11:21 1.592 1.998
test gas agip F123 shell 01/08/2018 11:21 02/08/2018 05:26 1.592 2.110
test gas agip F123 Ionic 02/08/2018 05:26 03/08/2018 05:25 1.598 2.114
test gas agip F123 meta 03/08/2018 05:25 04/08/2018 05:20 1.598 2.134
test gas agip F123 robo 04/08/2018 05:20 05/08/2018 05:24 1.598 1.989
test gas agip F123 dino 01/08/2018 05:26 01/08/2018 11:21 1.592 1.987
test gas agip F123 dino 01/08/2018 11:21 02/08/2018 05:26 1.592 2.456
test gas agip F123 dino 02/08/2018 05:26 03/08/2018 05:25 1.598 3.456
test gas agip F123 dino 03/08/2018 05:25 04/08/2018 05:20 1.598 1.989
test gas agip F123 dino 04/08/2018 05:20 05/08/2018 05:24 1.598 1.990
Я проверил InsertRow
и rbind
, но ни то, ни другое не работает.
Есть идеи?
Спасибо.
Ответ №1:
Чтобы объединить наборы данных, кажется, что хорошим решением является использование только rbind
наборов данных при использовании merge
для привязки наборов данных к ограничениям времени начала / окончания. В приведенном ниже примере rbind
функция вкладывает merge
условия для начальной и конечной дат:
library('data.table')
z <- rbind(
x = x,
y = merge(x[, .(code, starttime.x = starttime, endtime.x = endtime, price)], y,
by = 'code',
allow.cartesian = TRUE,
all.x = TRUE)[starttime.x < starttime amp; endtime.x > endtime,
.SD,
.SDcols = c(paste0(names(y)), 'price')])
z
Вывод:
NN gpn sitename code Brand starttime endtime price otherprice
1: test gas agip F123 bp 2018-08-01 00:26:49 2018-08-01 06:21:07 1.592 1.998
2: test gas agip F123 shell 2018-08-01 06:21:07 2018-08-02 00:26:39 1.592 2.110
3: test gas agip F123 ionic 2018-08-02 00:26:39 2018-08-03 00:25:59 1.598 2.114
4: test gas agip F123 meta 2018-08-03 00:25:59 2018-08-04 00:20:37 1.598 2.134
5: test gas agip F123 robo 2018-08-04 00:20:37 2018-08-05 00:24:28 1.598 1.989
6: test gas agip F123 dino 2018-08-01 06:23:19 2018-08-02 00:09:59 1.592 2.456
7: test gas agip F123 dino 2018-08-02 00:43:19 2018-08-03 00:20:00 1.598 3.456
8: test gas agip F123 dino 2018-08-03 00:53:19 2018-08-04 00:13:20 1.598 1.989
9: test gas agip F123 dino 2018-08-04 01:09:17 2018-08-05 00:23:20 1.598 1.990
Комментарии:
1. ОК. Это выглядит лучше, но все еще есть пара вещей. 1. допустим, мы переименовываем ‘y $ price’ в ‘y $ otherprice’, и ‘цена’ должна быть из ‘x’, только тогда как мы можем этого добиться? 2. Слияние должно быть соединением по левому краю, что означает, что должны быть возвращены все строки из ‘x’. Любые идеи о том, как настроить код для учета вышеупомянутых изменений. Спасибо
2. Давайте используем следующий dput для ‘y’, который я обновил в вопросе.
3. Хорошо — я скорректировал код, чтобы он соответствовал новым данным. «Цена» теперь относится только к значениям из таблицы «x». Объединение по левому краю достигается путем установки для
all.x
параметра значения TRUE вmerge
функции.4. Это выглядит хорошо, но по-прежнему отсутствует одно наблюдение из ‘x’, которое не соответствовало наблюдению в ‘y’. Таким образом, общее количество наблюдений в результате должно составлять 9, поскольку наблюдение из ‘y’, которое не соответствует ни одному из ‘x’, должно быть удалено только при сохранении всех строк из x. Спасибо.
5. Я удалил начальное / конечное подмножество в элементе «x», которое, как я думаю, препятствовало отображению всех строк.
unique
Это просто гарантирует, что вы не получите повторяющиеся записи. Я думаю, вы также могли бы просто заменить первый аргумент просто «x», поскольку слияние больше ничего не делает в этом примере. Что вы думаете?
Ответ №2:
Мы можем объединить, используя dplyr
, однако есть несколько предостережений из-за предоставленной структуры. Из dput()
мы видим, что у y
этого sitename
элемента нет starttime
переменной, starttime
и brand
являются факторами и их необходимо преобразовать в posixct, а переменная y
в Brand
имеет строчную букву «b», но в x
«в» — заглавную «B».
Учитывая эти наблюдения, мы можем сделать следующее:
# Change time to posixct to be consistent with x.
# NOTE: You may have to adjust the time zone
y$starttime = as.POSIXct(y$starttime)
y$endtime = as.POSIXct(y$endtime)
# Chance 'brand' to 'Brand'
colnames(y)[colnames(y)=="brand"] = "Brand"
# Change other variabes as mentioned in commen
y$otherprice = y$price
y$price = x$price
y$sitename = x$sitename
Мы можем создать подмножества, которые удовлетворяют указанным критериям (т. Е. выбрать подмножество x
и y
, где x$starttime < y$starttime
и x$endtime > y$endtime
)
# Create subsets which match criteria
x.subset = subset(x, subset = x$starttime < y$starttime amp; x$endtime > y$endtime)
y.subset = subset(y, subset = x$starttime < y$starttime amp; x$endtime > y$endtime)
Теперь мы можем связать подмножества вместе
# Row bind
library(dplyr)
z = dplyr::bind_rows(x.subset, y.subset)
> z
NN gpn sitename code Brand starttime endtime price otherprice
1: test gas agip F123 bp 2018-08-01 00:26:49 2018-08-01 06:21:07 1.592 1.998
2: test gas agip F123 shell 2018-08-01 06:21:07 2018-08-02 00:26:39 1.592 2.110
3: test gas agip F123 ionic 2018-08-02 00:26:39 2018-08-03 00:25:59 1.598 2.114
4: test gas agip F123 meta 2018-08-03 00:25:59 2018-08-04 00:20:37 1.598 2.134
5: test gas agip F123 robo 2018-08-04 00:20:37 2018-08-05 00:24:28 1.598 1.989
6: test gas agip F123 dino 2018-08-01 00:33:19 2018-08-01 06:08:20 1.592 1.987
7: test gas agip F123 dino 2018-08-01 06:23:19 2018-08-02 00:09:59 1.592 2.456
8: test gas agip F123 dino 2018-08-02 00:43:19 2018-08-03 00:20:00 1.598 3.456
9: test gas agip F123 dino 2018-08-03 00:53:19 2018-08-04 00:13:20 1.598 1.989
10: test gas agip F123 dino 2018-08-04 01:09:17 2018-08-05 00:23:20 1.598 1.990
Комментарии:
1. Все выглядит хорошо, но цена из y должна быть указана в столбце «other price», а «цена» должна совпадать с ценой для сайта в «x». Для sitename мы можем считать, что это то же самое. Кроме того, условие требует проверить, является ли время начала в «x» меньше, чем время начала в «y», и «время окончания» в «x» больше, чем время окончания в «y». Как я могу определить это условие при выполнении rbind?
2. код @syebill изменен с учетом запрошенных изменений.
3. Я также изменил структуру. Важной вещью является проверка времени. Есть идеи о том, как это настроить? Новые dput отражают правильные типы данных. Также вышеупомянутое решение работает, единственное, чего не хватает, это проверки времени. Вы предлагаете поместить rbind в инструкцию «if_else»?
4. @syebill не могли бы вы, пожалуйста, подробнее рассказать о проверке времени, на которую вы ссылаетесь?
5. @syebill : Я отредактировал свой ответ и добавил больше кода. Теперь есть этап фильтрации, на котором мы выбираем подмножества
x
иy
, которые удовлетворяют критериям, упомянутым в вашем комментарии, затем мы объединяем подмножества вместе. Это должно решить проблему. Пожалуйста, дайте мне знать.