これは、大きなテキスト ファイルからのサンプリングという課題に対する純粋な 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, ...)
}
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, ...)
}