从每组中提取N.

时间:2017-07-24 08:03:35

标签: bash awk sed split

我有一个包含两列的csv文件:'id'和'values'

id可以在文件中多次出现,具有不同的值。我想对数据进行分层抽样,以获得一个较小的文件,其中包含每个id的确切或最多N个。

示例输入:

    a    1,2,3
    a    2,2,3
    a    2,2,3
    a    2,4,3
    a    4,2,3
    a    4,4,4
    b    3,4,4
    b    8,8,8
    b    3,3,3
    c    4,5,6
    c    5,5,4

期望输出(N = 2):

    a    1,2,3
    a    2,2,3
    b    3,4,4
    b    8,8,8
    c    4,5,6
    c    5,5,4

此时我并不关心群体中的哪个身份,而是随机的奖励积分。

由于文本文件可能非常大,我更喜欢内存高效(linux)命令行解决方案(即bash,awk,sed等)

4 个答案:

答案 0 :(得分:2)

这是awk中的一个,实现某种随机性。它读取文件两次。在第一轮中,它使用 some 计算键和第二输出记录的一种概率。没有经过广泛测试,但它应该避免被零除,并且如果概率之神在此之前没有进行干预,则返回每个键的最后2个记录:

$ awk -v seed=$RANDOM -v n=2 '  # n is the count of keys wanted
BEGIN {
    srand(seed)                 
}
NR==FNR {                       # on the first run
    nc[$1]=n                    # ncound for each key (2)
    c[$1]++                     # count of keys
    next
}
{
    if(nc[$1]>0 && c[$1]>0 && (nc[$1]/c[$1]/(1-rand()))>1) {
        print
        nc[$1]--                # reduce n count for key when printing
    }
    c[$1]--                     # keys left counter reduces at each iteration
}' file file
a    1,2,3
a    4,2,3
b    8,8,8
b    3,3,3
c    4,5,6
c    5,5,4

另一次出场:

a    2,2,3
a    4,2,3
b    3,4,4
b    8,8,8
c    4,5,6
c    5,5,4

( nc[$1] / c[$1] / (1-rand()) ) > 1这可以保证如果之前没有打印过,则返回每个键的2个(或n)个最后记录,例如nc=2; c=2然后nc/c==1和{{ 1}}总是。 1/[0-1[ > 1返回范围rand()中的值,并避免[0-1[ /0随机分布可能不均匀。

答案 1 :(得分:1)

根据@Sundeep的建议,我使用带有数组[id]计数结构的shuf和awk(对于N = 10)做出了解决方案:

shuf ./data.csv | awk '{count[$1]++} {if (count[$1] < 10)print $1, $2}' ./data.csv 

这需要每个id的前10项。

答案 2 :(得分:0)

[akshay@localhost tmp]$ awk -v n=2 '++arr_seen[$1] <=n'  file
    a    1,2,3
    a    2,2,3
    b    3,4,4
    b    8,8,8
    c    4,5,6
    c    5,5,4

<强>输入

[akshay@localhost tmp]$ cat file
    a    1,2,3
    a    2,2,3
    a    2,2,3
    a    2,4,3
    a    4,2,3
    a    4,4,4
    b    3,4,4
    b    8,8,8
    b    3,3,3
    c    4,5,6
    c    5,5,4

答案 3 :(得分:0)

$ n=2; awk -v n=$n 'arr[$1]<n{arr[$1]++;print $0}' file
    a    1,2,3
    a    2,2,3
    b    3,4,4
    b    8,8,8
    c    4,5,6
    c    5,5,4

简要说明,

  • n=2:将所需的显示时间设置为bash变量n
  • arr[$1]<n:id将是数组的键,每个id的值将是每个键的值。如果是密钥<n的值,请打印该行,然后arr[$1]++