当前位置:  开发笔记 > 运维 > 正文

随机从文件中选择行而不用Unix扼杀它

如何解决《随机从文件中选择行而不用Unix扼杀它》经验,为你挑选了6个好方法。

我有一个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

cadrian.. 86

如果你有很多行,你确定你想正是 1%或统计估计就足够了?

在第二种情况下,每行只需1%随机...

awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01) print $0}'

如果你想要标题行加上随后的行样本,请使用:

awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01 || FNR==1) print $0}'

@Steven:理论上是的,几乎没有.对于OP的1000万行文件(由泊松分布给出),不打印行的概率大约为10 ^ -43430.通过猜测第一次尝试,相当于破解144*千字节*加密密钥. (10认同)

@Steven:不.算法需要正确*足够*.在这种情况下,它是正确的. (8认同)

好的,但是,正确的_algorithm_需要是正确的,而不是"非常可能是正确的".恕我直言. (4认同)

此外,对于OP的情况(10 ^ 7行),所选元素数量在10,000的1%内的可能性为99.8%. (3认同)

请注意,此算法会偏向较长的线条.如果要对此进行校正,则必须对采样进行加权(例如,采样线经常延长2倍的采样线).确切地说,如何做到这一点留给读者练习(提示:建立线长的经验分布). (2认同)

这里提到的正则表达式是否匹配每一行?如果是这样,你是否只是这样做,因为这是一种避免在每一行上进行for循环的聪明方法? (2认同)


Bill.. 53

你使用awk,但我不知道是否需要它.如果不是,这里有一个简单的方法来做w/perl(并且不将整个文件加载到内存中):

cat your_file.txt | perl -n -e 'print if (rand() < .01)'

(更简单的形式,来自评论):

perl -ne 'print if (rand() < .01)' your_file.txt 

@Steven,阅读原帖.他的文件有10 ^ 7行.他没有获得输出的几率是.99 ^ 100000000.说这是不可接受的是荒谬的.如果您担心这种程度的错误,则不应使用计算机.由于光线射线,你更有可能得到不正确的输出. (17认同)

这个版本(第二个例子)很快疯狂.我刚刚在SSD上运行了一个15GB的文件.有一个150MB的文件.尼斯. (3认同)


Steven Huwig.. 19

我在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  
} 


ashawley.. 16

这适用于大多数GNU/Linux机器.

$ shuf -n $(( $(wc -l < $file) / 100)) $file

如果GNU shuf命令不恰当地完成内存管理,我会感到惊讶.



1> cadrian..:

如果你有很多行,你确定你想正是 1%或统计估计就足够了?

在第二种情况下,每行只需1%随机...

awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01) print $0}'

如果你想要标题行加上随后的行样本,请使用:

awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01 || FNR==1) print $0}'


@Steven:理论上是的,几乎没有.对于OP的1000万行文件(由泊松分布给出),不打印行的概率大约为10 ^ -43430.通过猜测第一次尝试,相当于破解144*千字节*加密密钥.
@Steven:不.算法需要正确*足够*.在这种情况下,它是正确的.
好的,但是,正确的_algorithm_需要是正确的,而不是"非常可能是正确的".恕我直言.
此外,对于OP的情况(10 ^ 7行),所选元素数量在10,000的1%内的可能性为99.8%.
请注意,此算法会偏向较长的线条.如果要对此进行校正,则必须对采样进行加权(例如,采样线经常延长2倍的采样线).确切地说,如何做到这一点留给读者练习(提示:建立线长的经验分布).
这里提到的正则表达式是否匹配每一行?如果是这样,你是否只是这样做,因为这是一种避免在每一行上进行for循环的聪明方法?

2> Bill..:

你使用awk,但我不知道是否需要它.如果不是,这里有一个简单的方法来做w/perl(并且不将整个文件加载到内存中):

cat your_file.txt | perl -n -e 'print if (rand() < .01)'

(更简单的形式,来自评论):

perl -ne 'print if (rand() < .01)' your_file.txt 


@Steven,阅读原帖.他的文件有10 ^ 7行.他没有获得输出的几率是.99 ^ 100000000.说这是不可接受的是荒谬的.如果您担心这种程度的错误,则不应使用计算机.由于光线射线,你更有可能得到不正确的输出.
这个版本(第二个例子)很快疯狂.我刚刚在SSD上运行了一个15GB的文件.有一个150MB的文件.尼斯.

3> Steven Huwig..:

我在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  
} 



4> ashawley..:

这适用于大多数GNU/Linux机器.

$ shuf -n $(( $(wc -l < $file) / 100)) $file

如果GNU shuf命令不恰当地完成内存管理,我会感到惊讶.


如果你看一下源代码,你会看到`shuf`确实首先将整个文件读入内存,不幸的是.
`wc -l <​​$ file`不输出文件名,因此可以省略`cut`命令.

5> 小智..:

我不知道awk,但是有一个很好的技术可以解决你所描述的问题的更一般版本,并且在一般情况下,如果rand <0.01,它比文件返回行中for行要快得多方法,因此如果您打算执行上述许多(数千,数百万)次的任务,它可能会很有用.它被称为水库采样,该页面对其适用于您的情况的版本有很好的解释.



6> 小智..:

如何从大群体(未知大小)中均匀地采样N个元素的问题被称为水库采样.(如果您喜欢算法问题,请花几分钟尝试解决它,而无需在维基百科上阅读算法.)

对"水库采样"进行网络搜索会发现很多实施方案.这是实现你想要的Perl和Python代码,这是另一个讨论它的Stack Overflow线程.

推荐阅读
夏晶阳--艺术
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有