我有两个数据文件:
文件_1.in,包含超过 2k 行,例如“12 AB0001”:
10 AB0001 11 AC0002 12 AD0003 ...
我应该提取并解析gzip压缩文件的列表
*.gz
(大约1到3百万行)以创建一个名为lines(第二列)的输出文件文件_1.in。##comment.. ##comment.. #CHROM POS ID REF ALT QUAL FILTER INFO FORMAT AB0001 AC0002 AD0003 21 1234567 ab11111 G A 100 PASS info1;info2 GT 0|0 0|1 0|0 21 1234568 ab22222 C A 100 PASS info1,info2 GT 1:23:2 .:.:. 0:32:2 21 1234569 ab33333 A C 100 PASS info1;info2 GT 0|2 1|0 0|0
尝试不同的方法我得出这样的结论:
{
if(FNR==NR){list[$1]=$2;next}
if(!/^#/){
for(p in list){
split($p, sp, ":");
if (sp[1] != "0|0" && sp[1] != "0" && sp[1] != "."){
printf("%s %s %s %s %s %s %s %s %s %s\n",
$1, $2, $3, $4, $5, $6, $7, $8, $9, $p) >> out"/"list[p]".tmp"
}
}
}
}
通过命令行执行:
awk -v out="outfolder/" -f myscript.awk file_1.in <(zcat *.gz)
但仅创建一个文件就需要两个多小时。有办法改进我的代码吗?我认为大部分时间都花在了zcat
每个文件和似乎很慢的追加写入功能上。你怎么认为?
答案1
此代码在循环中执行大量处理,这些处理在迭代之间是相同的。 awks 没有复杂的循环优化来能够将其提升到循环之外:
for(p in list){
split($p, sp, ":");
if (sp[1] != "0|0" && sp[1] != "0" && sp[1] != "."){
在读取第一个文件来填充关联数组后,关联list
数组不会更改,但您会重复拆分索引值来测试此条件。相反,您可以遍历数组,然后删除不匹配的条目。或者...在处理时首先不要将这些条目插入数组file_1.in
!然后可以删除拆分和测试:循环无条件访问 中的每个条目list
。
printf("%s %s %s %s %s %s %s %s %s %s\n",
$1, $2, $3, $4, $5, $6, $7, $8, $9, $p) >> out"/"list[p]".tmp"
此处打印的材料对于循环的每次迭代都是相同的,除了最后一个%s
采用 的字段之外$p
。您可以使用sprintf
循环外部将九个字段格式化为字符串str
,然后执行以下操作: printf("%s %s", str, $p) >> out "/" list[p] ".tmp"
。
尚不清楚的是:假设
$p
中的表达式是一个适合索引字段的整数。所以整个逻辑看起来是假的:它在角色上进行分割,然后测试该分割的某些字段。如果预期为正整数,则不应包含任何冒号。您可能打算在这里测试第二列,即?printf
p
split
p
:
p
list[p]
除此之外,该程序可能会明显变慢。它维护着数千个打开的文件描述符,通过这些描述符将少量的材料添加到众多的输出文件中。数百万行来自压缩文件:对于每一行,循环都会迭代包含超过两千个条目的 assoc 数组,并将输出生成到许多不同的文件中。因此,数百万条压缩行变成了数十亿条未压缩行。
您可能想问自己将数据展开为该表示的目的是什么?如果是为了一些后续处理,也许可以使用更节省空间的表示方式。该awk
代码看起来像是在大量预先计算某种关联,某种数据库可能能够隐式处理该关联。