在bash中的已排序类别中随机抽取唯一样本
我有一个大的未排序的CSV文件(>4M记录)。每个记录都有一个类别,在前三列中进行了描述。记录的其余部分是地址数据,可能是唯一的,也可能不是唯一的在bash中的已排序类别中随机抽取唯一样本,bash,sorting,unix,random,command-line,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 我想随机抽取每个类别中的唯一记录样本(因此类别A1
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
有没有办法在每个类别中抽取几个随机样本记录
我认为一定有一种方法可以做到这一点,就是使用管道组合,
uniq
,awk
或shuf
,但我还没有弄明白。我更喜欢命令行解决方案,因为我想知道是否只使用bash就可以做到这一点。如果我理解正确-简单但不是非常有效的bash解决方案
csvfile="./ca.txt"
while read -r cat
do
grep "^$cat," "$csvfile" | sort -uR | head -5
done < <(cut -d, -f1-3 < "$csvfile" |sort -u)
csvfile=“./ca.txt”
而read-r猫
做
grep“^$cat”“$csvfile”| sort-uR | head-5
完成<灵感来自于在中使用sort-R
。这是对排序的GNU扩展,因此它可能无法在非GNU系统上工作
在这里,我们使用sort对整个文件进行一次排序,非类别字段按随机顺序排序。由于类别字段是主键,因此结果按类别顺序排列,以下字段的顺序为随机顺序
从那里,我们需要找到每个类别的前五个条目。可能有更黑客的方法可以做到这一点,但我使用了一个简单的awk
程序
sort -ut, -k1,3 -k4R "$csvfile" | awk -F, 'a!=$1$2$3{a=$1$2$3;n=0}++n<=5'
也可以将所有条目保留在awk中以避免排序,但这可能会慢得多,而且会占用大量内存。谢谢!我没有意识到可以在特定行上使用-R
选项。awk代码片段正是我想弄明白的。正如@rici提到的,sort
和-R
选项在mac OS X等非GNU系统上不可用。我下载了coreutils
(通过自制,brew安装coreutils
),它有一个与GNUsort
等效的gsort
命令,并包含-R
选项。@gunnar:sort-k4R
表示使用随机散列对字段从4到行尾进行排序。所以它不完全是一列。必须使用带分隔符的第一个键(-k1,3
表示从字段1到字段3的末尾)。如果希望排序键是单个列,则需要将列号写入两次:-k1,1
。
# 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()}'