在bash分类的类别中随机拉独特样本(Pull random unique samples with

2019-10-21 01:28发布

我有一个大的未排序的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

我想每个类别(在类别,这样5个独特的记录内拉的唯一记录进行随机抽样A1t ,从5个独特的记录C3e ,等等)。 我放在一起的部分解决方案使用sort 。 然而,这只是拉在每个类别一个非随机记录:

sort -u -t, -k1,3

有没有一种方法,以每个类别中拉几个随机抽样记录?

我认为必须有办法通过使用管道的组合来做到这一点uniqawkshuf ,但一直没能弄明白。 因为我想知道这是否可能只使用bash的我希望能有一个命令行的解决方案。

Answer 1:

通过使用启发sort -R在通过jm666答案 。 这是一个GNU扩展sort ,所以它可能不会在非GNU系统的工作。

在这里,我们使用排序整个文件进行排序,以随机顺序排序的非类领域。 由于类别字段是主键,其结果是在类别顺序与以下字段中的随机顺序。

从那里,我们需要找到在每个类别中的前五个条目。 可能有hackier方法可以做到这一点,但我有一个简单的去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来避免排序,但是这可能是慢了很多,它会使用的内存量过高。



Answer 2:

如果我正确理解 - 简单,不是非常有效的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条记录(从随机排序列表)


文章来源: Pull random unique samples within sorted categories in bash