这是从大型文本文件中采样挑战的纯 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 解析结果并返回结果
reader(textConnection(c(hdr, buf), header=header, ...)
}
通过使用和搜索 R-devel邮件列表中readBin
Simon Urbanek 所建议的换行符,该解决方案可以变得更高效,但更复杂一些。这是完整的解决方案
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, ...)
}