Как агрегировать или считать из другого элемента данных с ограничением? - PullRequest
1 голос
/ 28 апреля 2019

У меня есть два data.frames, которые являются DF1 и DF2.

DF1 - запись пассажира, а DF2 - запись поезда.

Я просто хочу найти пользователя, который мог бы сесть только на один поезд. Я хочу выбрать только один поезд, включенный во время поездки пассажира. Поезд прибывает на посадочную станцию ​​после прибытия пассажира, а поезд прибывает на посадочную станцию ​​до выхода пассажира. DF2 $ ЧЭС> DF1 $ ЧЭС & DF2 $ АСЕК

Если DF2 соответствует ограничениям, то я хочу извлечь его, как показано ниже (например, BSTN - станция посадки, ASTN - станция посадки)

--psuedo code--
DF3<-subset(DF2, BSTN==DF1$BSTN & ASTN==DF1$ASTN & BSEC>DF1$BSEC & ASEC<DF1$ASEC)

if nrow(DF3)==1 then cbind(DF1,DF2)

--my code now--
for(i in 1:nrow(DF1)){
  DF1.1<-DF1[i,]
  DF3<-subset(DF2, BSTN1==DF1.1$BSTN & ASTN1==DF1.1$ASTN & BSEC1>DF1.1$BSEC & ASEC1<DF1.1$ASEC)

if(nrow(DF3)==1)(aa<-bind_cols(DF1.1,DF3))
  temp.res<-bind_rows(temp.res,aa)
  }

Однако для цикла for требуется слишком много времени, поскольку суммарные данные для DF1 составляют около 8 000 000 строк, а для DF 2 - около 100 000 000.

существует ли какой-либо метод для более быстрого вычисления с помощью пакетов или функций (агрегатов)?

Я хочу получить данные и результат,

DF1

ID  BSTN     ASTN   BSEC    ASEC
1   2520    2516    200079  21071
2   2520    2516    200079  51071   
3   228     2516    300079  31071   

DF2

TRNID   BSTN     ASTN   BSEC    ASEC
1       2520    2516    200080  21061   
2       2520    2516    400079  41231   
3       2520    2516    500079  52171   
4       2520    2516    600079  60101
5       228     2516    300100  31061   
6       228     2516    400079  41231   
7       228     2516    500079  52171   
8       228     2516    600079  60101   

Рез

ID  BSTN     ASTN   BSEC    ASEC    TRNID   BSTN     ASTN   BSEC    ASEC
1   2520    2516    200079  21071   1       2520    2516    200080  21061
3   228     2516    300079  31071   5       2520    2516    300100  31061

СПАСИБО !!

Ответы [ 2 ]

2 голосов
/ 28 апреля 2019

Вот один из вариантов использования sqldf

library(sqldf)
sqldf("SELECT a.ID, a.BSEC As df1BSEC,a.ASEC As df1ASEC, b.TRNID, b.BSEC As df2BSEC, b.ASEC As df2ASEC
      FROM df1 a
      LEFT JOIN df2 b on 
      b.BSEC > a.BSEC AND b.ASEC < a.ASEC
             GROUP BY a.ID
             Having COUNT(*) = 1")

  ID df1BSEC df1ASEC TRNID df2BSEC df2ASEC
1  1  200079   21071     1  200080   21061
2  3  300079   31071     5  300100   31061
1 голос
/ 28 апреля 2019

Исходя из вашей попытки и описания, это то, что я придумал

do.call(rbind, lapply(seq_len(nrow(df1)), function(i) {
  inds <- with(df1, BSTN[i] == df2$BSTN & ASTN[i] == df2$ASTN & 
                    BSEC[i] < df2$BSEC & ASEC[i] > df2$ASEC)
  if(sum(inds) == 1) 
      cbind(df1[i, ], df2[inds, ])
}))

#  ID BSTN ASTN   BSEC  ASEC TRNID BSTN ASTN   BSEC  ASEC
#1  1 2520 2516 200079 21071     1 2520 2516 200080 21061
#3  3  228 2516 300079 31071     5  228 2516 300100 31061

Для каждой строки df1 мы cbind соответствуют df2 строке, если в * 1007 есть только одна строка* который удовлетворяет условию.

...