Как сделать то же самое в R, что мы делаем, используя CROSS APPLY в SQL Server?

то есть как запустить условие для каждой строки во внешнем фрейме данных для каждой строки во внутреннем фрейме данных) У меня есть два фрейма данных:

Тестировать

   Origin.State Dest.State  Ship.Date Cost
1            IL         NY 2015-03-25   10
2            IL         NY 2015-03-25   10
3            IL         NY 2015-03-24   10
4            IL         NY 2015-03-23   10
5            IL         NY 2015-03-18   10
6            PA         NY 2015-04-29   10
7            PA         NY 2015-04-29   10
8            PA         NY 2015-04-27   10
9            PA         NY 2015-04-24   10
10           PA         NY 2015-03-01   10
11           IL         TX 2015-05-18   10
12           IL         TX 2015-05-18   10
13           IL         TX 2015-05-14   10
14           IL         TX 2015-05-12   10
15           IL         TX 2015-05-13   10

TestShipmentGroup1

   Origin.State Dest.State  Ship.Date
1            IL         NY 2015-03-25
2            IL         NY 2015-03-24
3            IL         NY 2015-03-23
4            IL         NY 2015-03-18
5            PA         NY 2015-04-29
6            PA         NY 2015-04-27
7            PA         NY 2015-04-24
8            PA         NY 2015-03-01
9            IL         TX 2015-05-18
10           IL         TX 2015-05-14
11           IL         TX 2015-05-12
12           IL         TX 2015-05-13

Я пытаюсь применить условия, показанные ниже, к каждой строке кадра данных ToTest, используя каждую строку кадра данных TestShipmentGroup1 за раз.

for (i in 1: nrow(TestShipmentGroup1))
{
TestShipmentGroup1%>%
  select(Origin.State,Dest.State,Ship.Date)
ToTest%>%
  select(Origin.State, Dest.State,Ship.Date,Cost) %>% 
  filter (((ToTest$Ship.Date >= (TestShipmentGroup1$Ship.Date-7)) 
           & (ToTest$Ship.Date < TestShipmentGroup1$Ship.Date))
          & (ToTest$Origin.State == TestShipmentGroup1$Origin.State)
          & (ToTest$Dest.State == TestShipmentGroup1$Dest.State))}

person ash25    schedule 20.05.2016    source источник


Ответы (1)


Рассмотрим перекрестное соединение (возвращающее декартово произведение M X N из двух наборов) с использованием merge без переменных соединения, а затем примените условия фильтра. В качестве альтернативы также работает внутреннее соединение, объединенное в состояниях с последующим фильтром. Но сначала переименуйте столбцы, чтобы избежать конфликта:

library(dplyr)

...

names(ToTest) <- paste0(names(ToTest), "1")
names(TestShipmentGroup1) <- paste0(names(TestShipmentGroup1), "2")

# CROSS JOIN WITH FILTER
finaldf <- merge(select(ToTest, Origin.State1, Dest.State1, Ship.Date1),
                 select(TestShipmentGroup1, Origin.State2, Dest.State2, Ship.Date2)),
                 all=TRUE) %>%
                          filter (((Ship.Date1 >= (Ship.Date2-as.difftime(7, unit="days")))
                                  & (Ship.Date1 < Ship.Date2))
                                  & (Origin.State1 == Origin.State2)
                                  & (Dest.State1 == Dest.State2))

# INNER JOIN WITH FILTER
finaldf <- inner_join(select(ToTest, Origin.State1, Dest.State1, Ship.Date1),
                      select(TestShipmentGroup1, Origin.State2, Dest.State2, Ship.Date2), 
                 by = c("Origin.State1"="Origin.State2", "Dest.State1"="Dest.State2")) %>%
                          filter ((Ship.Date1 >= (Ship.Date2-as.difftime(7, unit="days")))
                                  & (Ship.Date1 < Ship.Date2))
person Parfait    schedule 20.05.2016
comment
Получилось парфе. Спасибо! Я действительно ценю твою помощь. :) - person ash25; 22.05.2016
comment
Есть ли более эффективный способ, чем слияние (), чтобы сделать то же самое, потому что это занимает слишком много времени для 20 000 записей, и мне нужно сопоставить каждую запись из TestShipmentGroup1 примерно с 3 записями lacs в данных ToTest? - person ash25; 23.05.2016
comment
Что слишком долго? 5 минут? 1 час? Попробуйте добавить новый столбец key=1 в оба фрейма данных и объединить его с ключом в by. Также изучите перекрестное соединение пакета data.table. См. это: stackoverflow.com/ questions/10600060/how-to-do-cross-join-in-r. - person Parfait; 23.05.2016
comment
Это заняло около 30-35 минут, и я добавил ключ = 1, а затем объединил его, он работал быстро, но показал, что у R закончилась память. Я попытался увеличить память, но это не сработало. - person ash25; 25.05.2016
comment
Я сделал это: res‹-setkey(ToTest[,c(k=1,.SD)],k)[TestShipmentGroup[,c(k=1,.SD)],allow.cartesian=TRUE][,k: =NULL]%›% filter ((Ship.Date ›= (Ship.Date2-as.difftime(7, unit=days))) & (Ship.Date ‹ Ship.Date2) & (Origin.State == Origin. State2) & (Dest.State == Dest.State2)) - person ash25; 25.05.2016
comment
Теперь я выполняю тот же запрос к очень большому набору данных, и из-за декартова произведения ему не хватает памяти. Можно ли как-нибудь избежать декартова произведения и при этом добиться тех же результатов? Любая помощь приветствуется. - person ash25; 14.07.2016
comment
Хммм... Интересно, почему я предложил Cross Join, так как Inner Join или обычное слияние в Штатах тоже работает. Смотрите обновленный код. - person Parfait; 14.07.2016
comment
Когда я запустил его, он выдал мне эту ошибку: Ошибка в выборе (ToTest, Origin.State1, Dest.State1, Ship.Date1): неиспользуемые аргументы (Origin.State1, Dest.State1, Ship.Date1) - person ash25; 14.07.2016
comment
Вы переименовали столбцы в ToTest и TestShipmentGroup1 в первых двух строках? - person Parfait; 14.07.2016