【问题标题】:How can I perform full outer joins of large data sets in R?如何在 R 中执行大型数据集的完全外连接?
【发布时间】:2013-06-02 14:54:43
【问题描述】:

我正在尝试在 R 中对一组中等规模的数据集进行数据分析。我需要做的一项分析要求我对大约 24-48 个文件进行完全外部连接,每个文件有大约 60 列和多达 450,000 行。所以我经常遇到内存问题。

我认为 ffbase 或 sqldf 会有所帮助,但显然它们中的任何一个都不可能完全外连接。

有解决方法吗?我还没有找到的包裹?

【问题讨论】:

  • 查看data.table。你有多少内存?
  • 另外,你怎么认为 sqldf 不能做全外连接? sqlite 有点棘手,因为您必须进行左/右连接然后合并它们,但 sqldf 也支持其他数据库后端......
  • 如果您在 sqldf 中使用外连接语句编写,它会发出警告,指出尚不支持显式外连接。
  • 消息说不支持 RIGHT 和 FULL 外连接。还剩下一个,这就是你所需要的。更不用说除了 SQLite 之外,您还有其他可用的数据库后端。
  • 但是只有 3-4 GB 的 RAM,我突然怀疑,无论使用什么方法,在 25 个以上的表上进行外连接是否会有很多运气,每个表都有数十万行你在用吗?

标签: r bigdata outer-join sqldf ffbase


【解决方案1】:

这是一个简单的例子,说明了如何对多个数据集进行外部连接:

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 中通过 exact same way 完成的。我对 postgres 不太熟悉,但this 问题肯定表明在那里也可以进行完全外部连接。

【讨论】:

  • 我做了上述但不知何故我得到了两倍。与合并相反的行数(x = dat1, y = dat2, by.x = "x", by.y = "y", all = T)。我不知道为什么!
  • @NikhilVidhani 我不确定你的意思。你写的那个代码会返回一个错误,因为by.y = "y"应该是by.y = "w",在这种情况下输出和上面一样。
  • 这仅适用于dat1dat2 中没有重复行的情况,这里就是这种情况。 UNION 返回唯一行并删除重复项。
  • @Waldi 对答案的编辑只需添加一条注释,即可以使用 UNION 或 UNION ALL 取决于是否要保留重复项,这比说答案“不”的评论更有帮助t 工作”,这在技术上是不正确的。
  • @Joran,在发表我的评论之前,我赞成您的回答,因为我发现它在这种情况下有用且相关。但是,我仍然认为我的评论很有帮助,因为如果您使用 UNION ALL,您将获得双倍数量的 common rows,这可能不是我们想要的,并且与 FULL OUTER JOIN 不同.
【解决方案2】:

如果您使用的是 ffbase,如果您将 expand.ffgrid 与 merge.ffdf 结合使用,您可以获得所需的完全外连接结果。 expand.ffgrid 类似于 expand.grid 但与 ff 向量一起使用,因此它不会溢出您的 RAM,merge.ffdf 允许与另一个 ffdf 合并而不会溢出您的 RAM 并将数据存储在磁盘上。下面是一个例子。

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

【讨论】:

    【解决方案3】:

    这可能有效(注意:关键列必须是每个数据集中的第一列)。

    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)
    

    我并不是说它很快,但它可能会克服内存障碍。

    【讨论】:

    • 我正在处理更大的数据集。我已经尝试过你的方法,我得到“row.names&lt;-.data.frame(*tmp*, value = rownam[as.integer(i2)]) 中的错误:不允许重复的 'row.names'”在执行唯一性
    • 抱歉,不知道(从那以后我就没碰过R)。
    【解决方案4】:

    没有 sqldf,这是一个聪明而简单的解决方案:

    合并(a, b, by = "col", all = T)

    外汇

    【讨论】:

      猜你喜欢
      • 2012-01-08
      • 1970-01-01
      • 2011-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-11
      • 2014-05-14
      • 2010-10-31
      相关资源
      最近更新 更多