linux 随机读取一行,linux-从文件中随机选择行,而没有使用Unix拖尾

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值