Bash 从各组中提取N
我有一个csv文件,有两列:“id”和“值” id可以在文件中以不同的值出现多次。我想对数据进行分层抽样,以获得一个较小的文件,该文件正好包含,或者最多包含N个idBash 从各组中提取N,bash,awk,sed,split,Bash,Awk,Sed,Split,我有一个csv文件,有两列:“id”和“值” id可以在文件中以不同的值出现多次。我想对数据进行分层抽样,以获得一个较小的文件,该文件正好包含,或者最多包含N个id [akshay@localhost tmp]$ awk -v n=2 '++arr_seen[$1] <=n' file a 1,2,3 a 2,2,3 b 3,4,4 b 8,8,8 c 4,5,6 c 5,5,4 输入示例: a
[akshay@localhost tmp]$ awk -v n=2 '++arr_seen[$1] <=n' file
a 1,2,3
a 2,2,3
b 3,4,4
b 8,8,8
c 4,5,6
c 5,5,4
输入示例:
a 1,2,3
a 2,2,3
a 2,2,3
a 2,4,3
a 4,2,3
a 4,4,4
b 3,4,4
b 8,8,8
b 3,3,3
c 4,5,6
c 5,5,4
期望输出N=2:
a 1,2,3
a 2,2,3
b 3,4,4
b 8,8,8
c 4,5,6
c 5,5,4
在这一点上,我不关心从一个组的id是采取,但奖金点,如果它是随机的
由于文本文件可能非常大,我更喜欢内存高效的linux命令行解决方案,即bash、awk、sed等。根据@Sundeep的建议,我使用shuf和awk以及数组[id]计数结构为N=10制作了一个解决方案:
shuf ./data.csv | awk '{count[$1]++} {if (count[$1] < 10)print $1, $2}' ./data.csv
这将获取每个id的前10项
[akshay@localhost tmp]$ awk -v n=2 '++arr_seen[$1] <=n' file
a 1,2,3
a 2,2,3
b 3,4,4
b 8,8,8
c 4,5,6
c 5,5,4
简要说明
n=2:将所需的显示时间设置为bash变量n
arr[$1]这里是awk中的一个,实现某种随机性。它读取文件两次。在第一轮中,它计数键,在第二轮中,它以某种概率输出记录。未进行广泛测试,但应避免被零除,如果概率之神在此之前未干预,则返回每个密钥的最后2条记录:
$ awk -v seed=$RANDOM -v n=2 ' # n is the count of keys wanted
BEGIN {
srand(seed)
}
NR==FNR { # on the first run
nc[$1]=n # ncound for each key (2)
c[$1]++ # count of keys
next
}
{
if(nc[$1]>0 && c[$1]>0 && (nc[$1]/c[$1]/(1-rand()))>1) {
print
nc[$1]-- # reduce n count for key when printing
}
c[$1]-- # keys left counter reduces at each iteration
}' file file
a 1,2,3
a 4,2,3
b 8,8,8
b 3,3,3
c 4,5,6
c 5,5,4
另一次运行产生:
a 2,2,3
a 4,2,3
b 3,4,4
b 8,8,8
c 4,5,6
c 5,5,4
nc[$1]/c[$1]/1-rand>1这保证了如果之前没有打印任何记录,则返回每个键的2个或n个最后记录,例如nc=2;c=2,则nc/c==1和1/[0-1[>1始终。rand返回范围为[0-1]的值[为了避免/0,存在/1-随机分布,但可能不均匀。请添加您试图解决此问题的内容…使用awk,您可以使用id作为密钥的数组,如果该密钥最多被看到N次,则可以打印感谢提示,我对awk不是很熟悉。我使用您的建议创建了一个解决方案。对于随机,您可以使用ng like shuf data.csv | awk-v n='2''++seed[$1]很好的答案,并且能够使用种子使其可复制,这是非常棒的。但是,对我的案例来说,重复两次文件会使其不太实用。
a 2,2,3
a 4,2,3
b 3,4,4
b 8,8,8
c 4,5,6
c 5,5,4