在bash中的已排序类别中提取随机唯一样本

时间:2014-09-28 21:05:38

标签: bash sorting unix random command-line

我有一个大的未分类的CSV文件(> 4M记录)。每条记录都有一个类别,在前三列中有描述。记录的其余部分是地址数据,可能是也可能不是唯一的。

A, 1, c, address1  # the category for this record is A1t
A, 1, c, address2
C, 3, e, address3  # the category for this record is C3e
B, 2, a, address4

我想在每个类别中随机抽取唯一记录样本(因此A1t类别中的5条唯一记录,C3e中的5条唯一记录等)。我使用sort整理了部分解决方案。但是,它只在每个类别中提取一个非随机记录:

sort -u -t, -k1,3

有没有办法在每个类别中提取几个随机样本记录?

我认为必须有一种方法可以通过使用管道组合uniqawkshuf来实现这一目标,但我们无法弄清楚这一点。我更喜欢命令行解决方案,因为我有兴趣知道这是否可以仅使用bash。

2 个答案:

答案 0 :(得分:1)

如果我理解正确 - 简单,不是非常有效的bash解决方案

csvfile="./ca.txt"
while read -r cat
do
    grep "^$cat," "$csvfile" | sort -uR | head -5
done < <(cut -d, -f1-3 < "$csvfile" |sort -u)

分解

  • cut -d, -f1-3 < "$csvfile" - 过滤掉所有“类别”(前3个字段)
  • sort -u - 排序唯一类别
  • 表示每个唯一类别(while read...
  • grep "^$cat" "$csvfile"查找此类别中的所有行
  • sort -uR - 通过哈希对它们进行随机排序(注意,重复项具有相同的哈希值,采用唯一方式)
  • head -5打印前5条记录(来自随机排序的列表)

答案 1 :(得分:0)

受到answer by jm666sort -R使用的启发。这是sort的GNU扩展,因此它可能无法在非Gnu系统上运行。

在这里,我们使用sort对整个文件进行一次排序,非类别字段按随机顺序排序。由于类别字段是主键,因此结果按类别顺序排列,并具有以下字段的随机顺序。

从那里,我们需要找到每个类别中的前五个条目。可能有更糟糕的方法,但我选择了一个简单的awk程序。

sort -ut, -k1,3 -k4R "$csvfile" | awk -F, 'a!=$1$2$3{a=$1$2$3;n=0}++n<=5'

如果sort未随机化,则可以使用awk提取随机样本:

# Warning! Only slightly tested :)
sort -ut, "$csvfile" | awk -F, '
      function sample(){
        for(;n>5;--n)v[int(n*rand())+1]=v[n];
        for(;n;--n)print v[n]
      }
      a!=$1$2$3{a=$1$2$3;sample()}
      {v[++n]=$0}
      END      {sample()}'

还可以将所有条目保存在awk中以避免排序,但这可能会慢很多,并且会使用过多的内存。