Merge 读取和合并计算机群集上的大型表

Merge 读取和合并计算机群集上的大型表,merge,parallel-processing,cluster-computing,lapply,Merge,Parallel Processing,Cluster Computing,Lapply,我需要将不同的大表(每个高达10Gb)合并到一个表中。为此,我使用了一个在Linux上运行的50+内核和10+Gb Ram的计算机集群 我总是以这样的错误消息结束:“无法分配大小为X Mb的向量”。 考虑到像memory.limit(size=X)这样的命令是特定于Windows的,并且不被接受,我找不到合并大型表的方法 欢迎任何建议 这是我使用的代码: library(parallel) no_cores <- detectCores() - 1 cl <- makeCluste

我需要将不同的大表(每个高达10Gb)合并到一个表中。为此,我使用了一个在Linux上运行的50+内核和10+Gb Ram的计算机集群

我总是以这样的错误消息结束:“无法分配大小为X Mb的向量”。 考虑到像
memory.limit(size=X)
这样的命令是特定于Windows的,并且不被接受,我找不到合并大型表的方法

欢迎任何建议

这是我使用的代码:

library(parallel)

no_cores <- detectCores() - 1
cl <- makeCluster(no_cores)

temp = list.files(pattern="*.txt$")
gc()

您可以只使用“合并”,例如:

`
mergedTable <- merge(table1, table2, by = "dbSNP_RSID")
If your samples have overlapping column names, then you'll find that the mergedTable has (for example) columns called Sample1.x and Sample1.y. This can be fixed by renaming the columns before or after the merge.

Reproducible example:

x <- data.frame(dbSNP_RSID = paste0("rs", sample(1e6, 1e5)),
  matrix(paste0(sample(c("A", "C", "T", "G"), 1e7, replace = TRUE),
    sample(c("A", "C", "T", "G"), 1e7, replace = TRUE)), ncol = 100))
y <- data.frame(dbSNP_RSID = paste0("rs", sample(1e6, 1e5)),
  matrix(paste0(sample(c("A", "C", "T", "G"), 1e7, replace = TRUE),
    sample(c("A", "C", "T", "G"), 1e7, replace = TRUE)), ncol = 100))
colnames(x)[2:101] <- paste0("Sample", 1:100)
colnames(y)[2:101] <- paste0("Sample", 101:200)
mergedDf <- merge(x, y, by = "dbSNP_RSID")
`

mergedTable实现这一点的一种方法是使用python和dask。dask数据帧主要存储在磁盘上,而不是ram中—允许您处理大于ram的数据—并且可以帮助您通过巧妙的并行化进行计算。在这篇文章中可以找到一个关于大数据工作方法的不错的教程,这可能对你也有帮助。我还建议查看有关dask性能的文档。要明确的是,如果您的数据可以在RAM中使用常规的R数据帧或pandas数据帧,则会更快

这里有一个dask解决方案,它假设您在表中命名了列,以对齐concat操作。如果你对我们需要考虑的数据有什么特别的要求,请加上你的问题。
import dask.dataframe as dd
import glob

tmp = glob.glob("*.txt")

dfs= []
for f in tmp:
    # read the large tables
    ddf = dd.read_table(f)
    # make a list of all the dfs
    dfs.append(ddf)

#row-wise concat of the data
dd_all = dd.concat(dfs)
#repartition the df to 1 partition for saving
dd_all = dd_all.repartition(npartitions=1)

# save the data 
# provide list of one name if you don't want the partition number appended on
dd_all.to_csv(['all_big_files.tsv'], sep = '\t')
如果您只是想将所有表放在一起,那么可以在纯python中执行类似的操作。(您也可以使用linux cat/paste)


您是否需要将数据作为R数据帧使用?如果你有一个和你想要的一样大的数据帧,你能加载它吗?我的建议是使用像Dask(python)这样的库,如果需要操作,它可以处理更大的数据,而无需将数据全部加载到内存中。谢谢你的建议。问题实际上是加载表。我不一定要将它们合并为R df,所以我将继续尝试您的Python解决方案。另一种选择是使用BigQuery并使用SQL合并它们。我会随时通知您。您的群集计算节点上的RAM是什么?如果你对dask有问题,我可以举个例子。另一种选择是,如果您只是将行连接起来(我认为这是在rbind中发生的),则使用linux“cat”命令。或者,如果你需要更多的过滤控制,你可以设计一个解决方案,你可以一个接一个地读取每个文件,然后写出一个大文件,最多25个。我在dask上有点迷路了,tbh——举个例子也许真的能帮到我!非常感谢。是的,我觉得你肯定需要一个低内存的方法。我会发布一些我做的事情(这可能不是最好的方式),但我在集群上工作时也会遇到同样的问题。帮我举个例子-每个表的列顺序/列数是否相同?每个表都有标题吗?我们需要删除重复行或类似的内容吗?谢谢您的努力。问题不在于代码,而在于基础荷载问题。这是一张大桌子,每行高达15米。我有点卡住了。我用两个数据集制作了一个玩具示例。使用
dd_all.to_csv('*.csv')
(以下:
http://docs.dask.org/en/latest/dataframe-api.html#dask.dataframe.to_csv
)我可以打印两个分区(我开始使用的文件),但不能打印新的连接文件。知道为什么吗?啊,我明白了,说得好,我想它会让你像普通的熊猫一样拯救它。无论如何,问题是分区(它创建了一个大df,其中有两个用于处理数据的分区),所以您需要做的是在保存之前“重新分区”连接的dd_all数据帧,我将编辑上面的答案以包括此步骤,让我知道它是否有效我想我已经解决了问题,让我知道这些编辑是否符合您的要求。好的,python从周五开始运行。没有任何完成的迹象。线索?有趣的是,当我制作一个10g文件时,它似乎工作正常。你确定它真的在运行什么吗?您应该top/htop并查看节点上的内存消耗。
import dask.dataframe as dd
import glob

tmp = glob.glob("*.txt")

dfs= []
for f in tmp:
    # read the large tables
    ddf = dd.read_table(f)
    # make a list of all the dfs
    dfs.append(ddf)

#row-wise concat of the data
dd_all = dd.concat(dfs)
#repartition the df to 1 partition for saving
dd_all = dd_all.repartition(npartitions=1)

# save the data 
# provide list of one name if you don't want the partition number appended on
dd_all.to_csv(['all_big_files.tsv'], sep = '\t')
with open('all_big_files.tsv', 'w') as O:
    file_number = 0
    for f in tmp:
        with open(f, 'rU') as F:
            if file_number == 0:
                for line in F:
                    line = line.rstrip()
                    O.write(line + '\n')
            else:
                # skip the header line
                l = F.readline()
                for line in F:
                    line = line.rstrip()
                    O.write(line + '\n')
            file_number +=1