nev*_*int 51 unix linux awk random-sample file-processing
我有一个10 ^ 7行文件,其中我想从文件中随机选择1/100行.这是我所拥有的AWK代码,但它会预先包含所有文件内容.我的PC内存无法处理这样的问题.还有其他办法吗?
awk 'BEGIN{srand()}
!/^$/{ a[c++]=$0}
END {
for ( i=1;i<=c ;i++ ) {
num=int(rand() * c)
if ( a[num] ) {
print a[num]
delete a[num]
d++
}
if ( d == c/100 ) break
}
}' file
Run Code Online (Sandbox Code Playgroud)
cad*_*ian 86
如果你有很多行,你确定你想正是 1%或统计估计就足够了?
在第二种情况下,每行只需1%随机...
awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01) print $0}'
Run Code Online (Sandbox Code Playgroud)
如果你想要标题行加上随后的行样本,请使用:
awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01 || FNR==1) print $0}'
Run Code Online (Sandbox Code Playgroud)
Bil*_*ill 53
你使用awk,但我不知道是否需要它.如果不是,这里有一个简单的方法来做w/perl(并且不将整个文件加载到内存中):
cat your_file.txt | perl -n -e 'print if (rand() < .01)'
Run Code Online (Sandbox Code Playgroud)
(更简单的形式,来自评论):
perl -ne 'print if (rand() < .01)' your_file.txt
Run Code Online (Sandbox Code Playgroud)
Ste*_*wig 19
我在Gawk写了这个确切的代码 - 你很幸运.部分原因是它保留了输入顺序.可能会有性能增强.
该算法在不事先知道输入大小的情况下是正确的.我在这里贴了一块玫瑰石.(我没有发布这个版本,因为它进行了不必要的比较.)
# Waterman's Algorithm R for random sampling
# by way of Knuth's The Art of Computer Programming, volume 2
BEGIN {
if (!n) {
print "Usage: sample.awk -v n=[size]"
exit
}
t = n
srand()
}
NR <= n {
pool[NR] = $0
places[NR] = NR
next
}
NR > n {
t++
M = int(rand()*t) + 1
if (M <= n) {
READ_NEXT_RECORD(M)
}
}
END {
if (NR < n) {
print "sample.awk: Not enough records for sample" \
> "/dev/stderr"
exit
}
# gawk needs a numeric sort function
# since it doesn't have one, zero-pad and sort alphabetically
pad = length(NR)
for (i in pool) {
new_index = sprintf("%0" pad "d", i)
newpool[new_index] = pool[i]
}
x = asorti(newpool, ordered)
for (i = 1; i <= x; i++)
print newpool[ordered[i]]
}
function READ_NEXT_RECORD(idx) {
rec = places[idx]
delete pool[rec]
pool[NR] = $0
places[idx] = NR
}
Run Code Online (Sandbox Code Playgroud)
ash*_*ley 16
这适用于大多数GNU/Linux机器.
$ shuf -n $(( $(wc -l < $file) / 100)) $file
Run Code Online (Sandbox Code Playgroud)
如果GNU shuf命令不恰当地完成内存管理,我会感到惊讶.
在这种情况下,通过水库采样来精确获取k值是非常简单的,awk令我惊讶的是,目前还没有解决方案表明这一点。我必须解决同样的问题,我编写了以下awk采样程序:
#!/usr/bin/env awk -f
BEGIN{
srand();
if(k=="") k=10
}
NR <= k {
reservoir[NR-1] = $0;
next;
}
{ i = int(NR * rand()) }
i < k { reservoir[i] = $0 }
END {
for (i in reservoir) {
print reservoir[i];
}
}
Run Code Online (Sandbox Code Playgroud)
如果另存为sample_lines并使其可执行,则可以像这样运行:./sample_lines -v k=5 input_file。如果k未指定,则默认使用 10。
然后弄清楚k是什么必须单独完成,例如通过设置-v "k=$(dc -e "$(cat input_file | wc -l) 100 / n")"