Любой другой процесс быстрее, чем sqldf в r - PullRequest
0 голосов
/ 03 июля 2018

У меня есть 2 кадра данных

df1 имеет 700 000 точек данных

  • ID1: категориальная переменная имеет более 400 категорий
  • Дата1: данные за 1 год
  • MST1: 2 уровня переменной 1/2
  • Номер подтверждения: уникальный идентификатор

пример данных:

ID1 ExtractDate1    MktSeg1 ConfirmationNo
145  3/7/2017          2    29083253
145  3/7/2017          1    29085100
145  3/7/2017          1    29085102
145  3/7/2017          1    29085106
145  3/7/2017          1    29084895
145  3/7/2017          1    29084953

df2 имеет 100 000 точек данных

  • ID2: категориальная переменная имеет более 400 категорий
  • Дата2: данные за 1 год
  • MST2: 2 уровня переменной 1/2
  • Conf No: уникальный идентификатор

Я хочу создать новую переменную, пометить df1, которая помечается как 1, когда номер подтверждения присутствует в df1 и df2, иначе 0

Я добился этого с помощью следующего:

combi1 <- sqldf("SELECT Distinct ID1,
            ExtractDate1,
            MktSeg1,
            ConfirmationNo,
            CASE
            WHEN confno IS NOT NULL
            THEN 1
            ELSE 0
            END AS 'Flag'
            FROM df1 
            LEFT JOIN df2  ON ID1 = ID2
            AND ExtractDate2 >= ExtractDate1
            AND ConfirmationNo = confno", drv = "SQLite")

На получение результатов уходит более 20-30 минут, есть ли лучший способ сделать это?

Я пробовал это

combi3 <- left_join(tbl_df(df1),tbl_df(df2),
                by = c("ID1" = "ID2" , "ExtractDate1" <= "ExtractDate2", "ConfirmationNo" = "ConfNo")) %>%
      select(distinct(ID1, ExtractDate1, MktSeg1, ConfirmationNo))

выдает следующую ошибку:

`by` can't contain join column `TRUE` which is missing from LHS

Ответы [ 2 ]

0 голосов
/ 03 июля 2018

Если вы хотите придерживаться sqldf, что может быть не самым быстрым вариантом, вы можете попробовать переписать свой запрос, чтобы использовать EXISTS:

combi1 <- sqldf("SELECT ID1,
            ExtractDate1,
            MktSeg1,
            ConfirmationNo,
            CASE WHERE EXISTS (SELECT 1 FROM df2
                WHERE ID1 = ID2
                AND ExtractDate2 >= ExtractDate1
                AND ConfirmationNo = confno)
            THEN 1
            ELSE 0
            END AS Flag
            FROM df1", drv = "SQLite")

Переключение на EXISTS означает, что нам больше не нужно использовать DISTINCT. Это также позволяет нам отказаться от левого соединения, поскольку логика может прекратить сканирование после первого совпадения.

Обратите внимание, что в реальной базе данных мы можем выполнить гораздо больше настроек. Для sqldf это может быть столько, сколько мы можем сделать.

0 голосов
/ 03 июля 2018

Используя предоставленные вами данные и аналогичные им для второго фрейма данных, вы можете использовать оператор %in%:

df1 <- read.table(text = "ID1 ExtractDate1    MktSeg1 ConfirmationNo
145  3/7/2017          2    29083253
                  145  3/7/2017          1    29085100
                  145  3/7/2017          1    29085102
                  145  3/7/2017          1    29085106
                  145  3/7/2017          1    29084895
                  145  3/7/2017          1    29084953", header = TRUE)

df2 <- read.table(text = "ID1 ExtractDate1    MktSeg1 ConfirmationNo
145  3/7/2017          2    29083253
                  145  3/7/2017          1    29085106
                  145  3/7/2017          1    29084895
                  145  3/7/2017          1    29084953
                  145  3/7/2017          1    29084899
                  145  3/7/2017          1    29084959", header = TRUE)

df1$conf_flag <- as.numeric(df1$ConfirmationNo %in% df2$ConfirmationNo)
df1
...