我有一个包含两列的csv文件:'id'和'values'
id可以在文件中多次出现,具有不同的值。我想对数据进行分层抽样,以获得一个较小的文件,其中包含每个id的确切或最多N个。
示例输入:
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
此时我并不关心群体中的哪个身份,而是随机的奖励积分。
由于文本文件可能非常大,我更喜欢内存高效(linux)命令行解决方案(即bash,awk,sed等)
答案 0 :(得分:2)
这是awk中的一个,实现某种随机性。它读取文件两次。在第一轮中,它使用 some 计算键和第二输出记录的一种概率。没有经过广泛测试,但它应该避免被零除,并且如果概率之神在此之前没有进行干预,则返回每个键的最后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}}总是。 1/[0-1[ > 1
返回范围rand()
中的值,并避免[0-1[
/0
随机分布可能不均匀。
答案 1 :(得分:1)
根据@Sundeep的建议,我使用带有数组[id]计数结构的shuf和awk(对于N = 10)做出了解决方案:
shuf ./data.csv | awk '{count[$1]++} {if (count[$1] < 10)print $1, $2}' ./data.csv
这需要每个id的前10项。
答案 2 :(得分:0)
[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
<强>输入强>
[akshay@localhost tmp]$ cat file
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
答案 3 :(得分:0)
$ n=2; awk -v n=$n 'arr[$1]<n{arr[$1]++;print $0}' 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]<n
:id将是数组的键,每个id的值将是每个键的值。如果是密钥<n
的值,请打印该行,然后arr[$1]++
。