我有一个大的未排序的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
有没有一种方法,以每个类别中拉几个随机抽样记录?
我认为必须有办法通过使用管道的组合来做到这一点uniq
, awk
或shuf
,但一直没能弄明白。 因为我想知道这是否可能只使用bash的我希望能有一个命令行的解决方案。
通过使用启发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来避免排序,但是这可能是慢了很多,它会使用的内存量过高。
如果我正确理解 - 简单,不是非常有效的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条记录(从随机排序列表)