Как я могу выполнять полные внешние соединения больших наборов данных в R?

Я пытаюсь выполнить анализ данных в R для группы наборов данных среднего размера. Один из анализов, которые мне нужно выполнить, требует, чтобы я выполнил полное внешнее соединение примерно между 24-48 файлами, каждый из которых имеет около 60 столбцов и до 450 000 строк. Так что я часто сталкивался с проблемами памяти.

Я думал, что ffbase или sqldf помогут, но, по-видимому, полное внешнее соединение невозможно ни с одним из них.

Есть ли обходной путь? Пакет, который я еще не нашел?


person Drew75    schedule 06.06.2013    source источник
comment
Загляните в data.table. Сколько у вас оперативной памяти?   -  person Simon O'Hanlon    schedule 06.06.2013
comment
Кроме того, почему вы думаете, что sqldf не может выполнять полные внешние соединения? sqlite немного сложен, так как вам нужно выполнять левое/правое соединение, а затем объединять их, но sqldf также поддерживает другие бэкэнды БД...   -  person joran    schedule 06.06.2013
comment
Если вы пишете в sqldf с оператором внешнего соединения, выдается предупреждение о том, что явно внешние соединения еще не поддерживаются.   -  person Drew75    schedule 06.06.2013
comment
В сообщении говорится, что внешние соединения RIGHT и FULL не поддерживаются. Остался один, и это все, что вам нужно. Не говоря уже о том, что у вас все еще есть другие бэкэнды БД, помимо SQLite.   -  person joran    schedule 06.06.2013
comment
Но имея всего 3-4 ГБ ОЗУ, я вдруг стал скептически относиться к тому, что вам повезет с внешними соединениями более 25 таблиц, каждая из которых содержит сотни тысяч строк, независимо от того, какой метод вы используете.   -  person joran    schedule 06.06.2013
comment
ОЗУ не обязательно является ограничением базы данных, если вы делаете это из памяти. С помощью sqldf укажите sqldf(..., dbname = tempfile()) .   -  person G. Grothendieck    schedule 06.06.2013
comment
tempfile() должен помочь с проблемой памяти, поэтому я хочу использовать sqldf. Я попробую с LEFT OUTER JOIN и посмотрю, возможно ли это.   -  person Drew75    schedule 07.06.2013
comment
Это работает с LEFT OUTER JOIN, но, возможно, мне следует опубликовать новый вопрос. Для второй задачи мне все еще нужно ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ для тех же файлов...   -  person Drew75    schedule 07.06.2013


Ответы (4)


Вот простой пример, иллюстрирующий, как выполнять внешние соединения нескольких наборов данных:

library(sqldf)
dat1 <- data.frame(x = 1:5,y = letters[1:5])
dat2 <- data.frame(w = 3:8,z = letters[3:8])
> 
> sqldf("select * from dat1 left outer join dat2 on dat1.x = dat2.w UNION 
+       select * from dat2 left outer join dat1 on dat1.x = dat2.w")
  x y  w    z
1 1 a NA <NA>
2 2 b NA <NA>
3 3 c  3    c
4 4 d  4    d
5 5 e  5    e
6 6 f NA <NA>
7 7 g NA <NA>
8 8 h NA <NA>

Вот оно, полное внешнее соединение с использованием sqldf и SQLite в качестве серверной части.

Как я уже упоминал, sqldf поддерживает больше серверных частей, чем SQLite. Один поиск в Google показывает, что полные внешние соединения выполняются точно так же в MySQL. Я менее знаком с postgres, но этот вопрос наверняка предполагает, что и там возможны полные внешние соединения.

person joran    schedule 08.06.2013
comment
Я сделал выше, но почему-то я получаю в два раза больше нет. строк, а не слияние (x = dat1, y = dat2, by.x = x, by.y = y, all = T). Я не имею понятия почему! - person Nikhil Vidhani; 01.12.2017
comment
@NikhilVidhani Я не понимаю, что ты имеешь в виду. Этот код, который вы написали, возвращает ошибку, потому что by.y = "y" должно быть by.y = "w", и в этом случае вывод такой же, как указано выше. - person joran; 01.12.2017
comment
Это работает, только если нет повторяющихся строк ни в dat1, ни в dat2, как здесь. UNION возвращает уникальные строки и удаляет дубликаты. - person Waldi; 24.04.2021
comment
@Waldi Редактирование ответа, просто добавление примечания о том, что можно использовать UNION или UNION ALL в зависимости от того, хотите ли вы сохранить дубликаты, было бы более полезным, чем комментарий о том, что ответ не работает, что технически неверно. - person joran; 27.04.2021
comment
@ Джоран, прежде чем опубликовать свой комментарий, я проголосовал за ваш ответ, потому что нашел его полезным и актуальным в данном случае. Тем не менее, я по-прежнему считаю, что мой комментарий полезен, потому что, если вы используете UNION ALL, вы получите двойное количество общих строк, что, вероятно, не то, что нужно, и отличает его от FULL OUTER JOIN. . - person Waldi; 27.04.2021
comment
Чтобы продемонстрировать это, вы можете просто запустить приведенный выше код с UNION ALL => 11 rows , но ожидается 8 строк. - person Waldi; 27.04.2021
comment
@Waldi В любом случае, я бы предпочел, чтобы вы просто улучшили ответ. Честно говоря, если бы это не был принятый ответ, я бы просто удалил его, чтобы не беспокоить. - person joran; 27.04.2021

Без sqldf вот умное и простое решение:

слияние (а, б, по = «столбец», все = Т)

FX

person FX Jollois    schedule 15.10.2014

Если вы используете ffbase, вы можете получить желаемый результат полного внешнего соединения, если объедините файл expand.ffgrid с merge.ffdf. expand.ffgrid похож на expand.grid, но работает с векторами ff, поэтому он не будет переполнять вашу оперативную память, а merge.ffdf позволяет объединяться с другим ffdf, не перегружая вашу оперативную память и сохраняя данные на диске. Пример ниже.

require(ffbase)
x <- ffseq(1, 10000)
y <- ff(factor(LETTERS))
allcombinations <- expand.ffgrid(x, y)
addme <- data.frame(Var1 = c(1, 2), Var2 = c("A","B"), measure = rnorm(2))
addme <- as.ffdf(addme)
myffdf <- merge(allcombinations, addme, by.x=c("Var1","Var2"), by.y=c("Var1","Var2"),  all.x=TRUE)
myffdf[1:10,]

Затем посмотрите delete rows ff-package, чтобы узнать, как создать подмножество полученного myffdf.

Посмотрите на ?ffbase::expand.ffgrid и ?ffbase::merge.ffdf

person Community    schedule 09.06.2013

Это может сработать (примечание: ключевой столбец должен быть первым столбцом в каждом наборе данных).

library(ff)
library(ffbase)

fullouterjoin <- function(ffdf1, ffdf2){

    # do a left outer join
    leftjoin <- merge(ffdf1, ffdf2, by = "key", all.x = TRUE)

    # do a right outer join (it's just a left outer join with the objects swapped)
    rightjoin <- merge(ffdf2, ffdf1, by = "key", all.x = TRUE)

    # swap the column orders (make ffd1 columns first and ffd2 columns later)
    srightjoin <- rightjoin[c(names(ffdf1), names(ffdf2)[2:length(ffdf2)])]

    # stack left outer join on top of the (swapped) right outer join
    stacked <- rbind(leftjoin, srightjoin)

    # remove duplicate rows
    uniques <- unique(stacked)

    # that's it
    return(uniques)
}

использование:

newffdf <- fullouterjoin(some_ffdf, another_ffdf)

Я не говорю, что это быстро, но это может преодолеть барьер памяти.

person Parzival    schedule 29.11.2013
comment
Я работаю с гораздо большими наборами данных. Я пробовал ваш метод и получаю сообщение об ошибке row.names<-.data.frame(*tmp*, value = rownam[as.integer(i2)]): дублирование «row.names» не разрешено при выполнении уникальной ‹- уникальной (сложенной) части. Вы хоть представляете, откуда это? - person Nikolay Nenov; 02.07.2014
comment
Извините, без понятия (с тех пор я не трогал R). - person Parzival; 02.07.2014