我有一个大的未分类的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
有没有办法在每个类别中提取几个随机样本记录?
我认为必须有一种方法可以通过使用管道组合uniq
,awk
或shuf
来实现这一目标,但我们无法弄清楚这一点。我更喜欢命令行解决方案,因为我有兴趣知道这是否可以仅使用bash。
答案 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 jm666中sort -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中以避免排序,但这可能会慢很多,并且会使用过多的内存。