linux-从文件中随机选择行,而没有使用Unix拖尾
我有一个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
10个解决方案
86 votes
如果您有那么多行,确定要精确地等于1%还是统计估计就足够了?
在第二种情况下,只需在每一行随机分配1%...
awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01) print $0}'
如果您希望标题行加上其后的随机行样本,请使用:
awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01 || FNR==1) print $0}'
cadrian answered 2020-01-17T09:13:28Z
53 votes
您使用了awk,但我不知道是否需要。 如果不是这样,这是一种使用perl的简单方法(并且无需将整个文件加载到内存中):
cat your_file.txt | perl -n -e 'print if (rand() < .01)'
(更简单的形式,来自评论):
perl -ne 'print if (rand() < .01)' your_file.txt
Bill answered 2020-01-17T09:13:52Z
19 votes
我用Gawk编写了这个确切的代码-真幸运。 之所以很长一段时间,部分是因为它保留了输入顺序。 可能可以提高性能。
这种算法是正确的,无需事先知道输入大小。 我在这里贴了一块罗塞塔石。 (我没有发布此版本,因为它进行了不必要的比较。)
原始主题:提交供您审核-以awk随机抽样。
# 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
}
Steven Huwig answered 2020-01-17T09:14:21Z
16 votes
这应该可以在大多数GNU / Linux机器上使用。
$ shuf -n $(( $(wc -l < $file) / 100)) $file
如果GNU shuf命令不恰当地执行了内存管理,我会感到惊讶。
ashawley answered 2020-01-17T09:14:46Z
5 votes
我不知道awk,但是有一种很棒的技术可以解决您所描述问题的更一般版本,并且在一般情况下,如果rand <0.01,它比文件返回行中的for行要快很多。 方法,因此如果您打算执行上述多次(数千,数百万)的任务,这可能会很有用。 这被称为储层采样,并且此页面对适用于您的情况的版本进行了很好的解释。
advait answered 2020-01-17T09:15:06Z
5 votes
如何从大量人口(未知大小)中均匀采样N个元素的问题被称为“水库采样”。 (如果您喜欢算法问题,请花几分钟时间尝试解决它,而无需阅读维基百科上的算法。)
在Web上搜索“储层采样”将找到许多实现。 这是实现所需功能的Perl和Python代码,这是讨论它的另一个Stack Overflow线程。
Tudor Bosman answered 2020-01-17T09:15:31Z
3 votes
您可以通过两步来完成:
遍历文件一次,只是计算有多少行
随机选择要打印的行的行号,并将其存储在排序列表(或一组)中
再次遍历文件,并在选定位置挑选出行
python中的示例:
fn = '/usr/share/dict/words'
from random import randint
from sys import stdout
count = 0
with open(fn) as f:
for line in f:
count += 1
selected = set()
while len(selected) < count//100:
selected.add(randint(0, count-1))
index = 0
with open(fn) as f:
for line in f:
if index in selected:
stdout.write(line)
index += 1
sth answered 2020-01-17T09:16:08Z
2 votes
在这种情况下,使用awk -v 'k=int('$(dc -e "$(cat FILE | wc -l) 0.01 * n")')'进行储油层采样以准确获取k值是微不足道的,我很惊讶还没有解决方案建议这样做。 我必须解决相同的问题,并编写了以下awk程序进行采样:
NR < k {
reservoir[NR] = $0;
}
NR >= k {
i = int(NR * rand());
if (i < k) {
reservoir[i] = $0;
}
}
END {
for (i in reservoir) {
print reservoir[i];
}
}
然后例如必须通过设置awk -v 'k=int('$(dc -e "$(cat FILE | wc -l) 0.01 * n")')'来确定k是什么。
kqr answered 2020-01-17T09:16:33Z
1 votes
与其等到最后随机选择1%的行,不如每100行“ / ^ $ /”中的行。 这样,一次只能容纳100条线路。
Travis Jensen answered 2020-01-17T09:16:53Z
1 votes
如果目的只是为了避免内存耗尽,并且该文件是常规文件,则无需执行存储库采样。 如果您在文件中进行两次遍历,就可以知道文件中的行数,一次获取行数(例如wc -l),一次选择样本:
file=/some/file
awk -v percent=0.01 -v n="$(wc -l < "$file")" '
BEGIN {srand(); p = int(n * percent)}
rand() * n-- < p {p--; print}' < "$file"
Stephane Chazelas answered 2020-01-17T09:17:13Z