使用 bigmemory 将 40 GB csv 文件读入 R
Posted
技术标签:
【中文标题】使用 bigmemory 将 40 GB csv 文件读入 R【英文标题】:Reading 40 GB csv file into R using bigmemory 【发布时间】:2013-03-10 02:15:39 【问题描述】:这里的标题很容易解释,但我将详细说明如下。我目前解决这个问题的一些技术是基于this问题中提出的解决方案。但是,我面临着一些挑战和限制,所以我想知道是否有人可能会尝试解决这个问题。我正在尝试使用bigmemory 包解决问题,但我遇到了困难。
目前的约束:
使用具有 16 GB RAM 的 linux 服务器 40 GB CSV 的大小 行数:67,194,126,114挑战
需要能够从 big.matrix 或等效数据结构中随机抽取较小的数据集(5-10 百万行)。 在解析为 big.matrix 或等效数据结构时,需要能够删除具有单个 NULL 实例的任何行。到目前为止,结果并不好。显然,我在某些事情上失败了,或者我只是不太了解bigmemory documentation。所以,我想我会在这里问一下是否有人使用过
关于这条攻击线的任何提示、建议等?还是我应该换成别的东西?如果这个问题与之前的问题非常相似,我深表歉意,但我认为数据规模比之前的问题大 20 倍左右。谢谢!
【问题讨论】:
文件内容的样本怎么样? 你到底哪里失败了? .csv 文件中有哪些类型的数据——都是double
s、int
s 还是其他? NULL
条目在文件中是如何表示的?有行/列名吗?而且,你试过什么?给定一个适当结构的 .csv,read.big.matrix
应该可以帮助您。
更多信息会很好,但为什么不将其导入 SQL,在那里做一些准备,然后将其加载到 R 中?
感谢您的建议。让我再看看我的数据,然后就我的问题与你们联系。
我建议查看 ff 包。您会将数据写入磁盘而不是内存。
【参考方案1】:
我不知道bigmemory
,但为了满足您的挑战,您不需要读取文件。只需管道一些 bash/awk/sed/python/whatever 处理来执行您想要的步骤,即扔掉NULL
行并随机选择N
行,然后读入。
这是一个使用 awk 的示例(假设您希望从具有 1M 行的文件中获取 100 条随机行)。
read.csv(pipe('awk -F, \'BEGINsrand(); m = 100; length = 1000000;
!/NULL/if (rand() < m/(length - NR + 1))
print; m--;
if (m == 0) exit;
\' filename'
)) -> df
我并不清楚您所说的 NULL
是什么意思,所以我使用了字面理解,但应该很容易修改它以满足您的需求。
【讨论】:
这实际上是一个非常好的答案,我曾经通过实施一个非常相似的解决方案解决了我的问题。谢谢你的回答。我会接受的。【参考方案2】:这是一个纯 R 解决方案,可以解决从大型文本文件中采样的挑战;它还有一个额外的优点,就是随机抽取 n 个样本。虽然将行解析为字符向量并且速度相对较慢,但效率并不算太低。
我们从一个函数签名开始,我们在其中提供一个文件名、我们想要绘制的样本的大小、随机数生成器的种子(这样我们就可以重现我们的随机样本!)、一个指示是否有一个标题行,然后是一个“读取器”函数,我们将使用它来将样本解析为 R 看到的对象,包括读取器函数可能需要的附加参数 ...
fsample <-
function(fname, n, seed, header=FALSE, ..., reader=read.csv)
该函数为随机数生成器提供种子,打开一个连接,并读入(可选)标题行
set.seed(seed)
con <- file(fname, open="r")
hdr <- if (header)
readLines(con, 1L)
else character()
下一步是读入一大块 n 行,初始化一个计数器,记录看到的总行数
buf <- readLines(con, n)
n_tot <- length(buf)
继续读取 n 行的块,当没有进一步的输入时停止
repeat
txt <- readLines(con, n)
if ((n_txt <- length(txt)) == 0L)
break
对于每个块,绘制n_keep
行的样本,行数与当前块中总行的比例成正比。这可确保在文件中对行进行均匀采样。如果没有要保留的行,请移至下一个块。
n_tot <- n_tot + n_txt
n_keep <- rbinom(1, n_txt, n_txt / n_tot)
if (n_keep == 0L)
next
选择要保留的行和要替换的行,并更新缓冲区
keep <- sample(n_txt, n_keep)
drop <- sample(n, n_keep)
buf[drop] <- txt[keep]
数据输入完成后,我们使用阅读器解析结果并返回结果
reader(textConnection(c(hdr, buf), header=header, ...)
通过使用readBin
并按照 Simon Urbanek 在 R-devel mailing list 上的建议搜索换行符,该解决方案可以变得更高效,但更复杂一些。
这是完整的解决方案
fsample <-
function(fname, n, seed, header=FALSE, ..., reader = read.csv)
set.seed(seed)
con <- file(fname, open="r")
hdr <- if (header)
readLines(con, 1L)
else character()
buf <- readLines(con, n)
n_tot <- length(buf)
repeat
txt <- readLines(con, n)
if ((n_txt <- length(txt)) == 0L)
break
n_tot <- n_tot + n_txt
n_keep <- rbinom(1, n_txt, n_txt / n_tot)
if (n_keep == 0L)
next
keep <- sample(n_txt, n_keep)
drop <- sample(n, n_keep)
buf[drop] <- txt[keep]
reader(textConnection(c(hdr, buf)), header=header, ...)
【讨论】:
感谢您发布代码,并感谢您提供出色的文档。你能不能用readBin
给我指出和举例?谢谢!以上是关于使用 bigmemory 将 40 GB csv 文件读入 R的主要内容,如果未能解决你的问题,请参考以下文章
使用 Spark 和 Scala 清理大小约为 40GB 的 CSV/Dataframe
使用 Pandas 或其他方法比较大型 (~40GB) 文本数据
在python中计算30GB + csv文件中双引号外的新行数