我有一个数据文件A.tsv
(字段分隔符= \t
):
id clade mutation
243 40A siti,toto,mumu
254
267 40B lala,sisi,sojo
和一个模板文件B.tsv
(字段分隔符 = \t
):
40A toto,xixi,saxa
40B lala,sojo,huhu
40C sasa,sisi,lala
基于他们的共同列(clade),我想比较A.tsv
来自模板的突变B.tsv
。我有两个问题:
B.tsv
如何在名为“missing_mutation”的新列中指示 中不存在的突变名称A.tsv
。- 如何在名为“remaining_mutation”的新列中指示存在于
A.tsv
(以字母 开头s
,不区分大小写)但不存在于 中的突变的名称B.tsv
。
C.tsv
看起来像这样:
id clade mutation missing_mutation remaining_mutation
243 40A siti,toto,mumu xixi,saxa siti
254
267 40B lala,sisi,sojo huhu sisi
我知道如何比较两个文件,如下所示:
awk -F"," -vOFS="," '
NR==FNR {
a[$2]=$3;
next
}
{ print $0,a[$2] }
' B.tsv A.tsv > C.tsv
但我不知道如何打印那些不匹配的内容。你有好主意吗?
答案1
下面的awk
程序为了方便使用了 GNU awk
(以“真正的双索引数组”的形式),应该可以解决这个问题。它旨在以您的两个文件作为参数按顺序调用B.txt
A.txt
(就像您在代码示例中所做的那样)。
#!/bin/awk -f
BEGIN{FS=OFS="\t"}
NR==FNR {
n_tmp[$1]=split($2,buff,/,/)
for (i=1;i<=n_tmp[$1];i++) mut_tmp[$1][i]=buff[i]
next
}
FNR==1 {
print $0,"missing_mutation","remaining_mutation"
}
FNR>1 {
n_curr=split($3,mutations,/,/)
mut_miss=0
mut_rem=0
# Find missing
for (j=1;j<=n_tmp[$2];j++)
{
for (i=1;i<=n_curr;i++)
{
if (mutations[i]==mut_tmp[$2][j]) break
}
if (i>n_curr) mut_miss=mut_miss ? mut_miss "," mut_tmp[$2][j] : mut_tmp[$2][j]
}
# Find remaining
for (i=1;i<=n_curr;i++)
{
for (j=1;j<=n_tmp[$2];j++)
{
if (mutations[i]==mut_tmp[$2][j]) break;
}
if (j>n_tmp[$2] && mutations[i]~/^[Ss]/) mut_rem=mut_rem ? mut_rem "," mutations[i] : mutations[i]
}
if (!mut_miss) mut_miss=""
if (!mut_rem) mut_rem=""
print $0,mut_miss,mut_rem
}
- 这将首先创建一个 clade nr 的关联表。与解析模板时的突变列表相比
B.tsv
,其中模板突变列表被显式分割成单个突变的数组。请注意,为了方便起见,我使用“双索引”数组mut_tmp
,其中第一个索引是分支编号。第二个是突变的索引号。突变的数量也存储在一个数组中n_tmp
。 - 解析时
A.tsv
,它会首先打印新的标头。 - 然后,对于每一行,它首先将字段 3 中的突变列表拆分为一个数组
mutations
。 - 然后,它将当前进化枝 ( ) 的模板突变列表中的每个条目
mut_tmp[$2]
与存在的突变 (mutations
) 进行比较,以填充“缺失突变”字段。 - 接下来,它将当前突变列表中的每个条目与当前进化枝的模板突变进行比较,以填充“剩余突变”字段,此外还检查突变是否以
s
或开头S
。
如果您没有可用的 GNU ,您可以通过替换awk
使其与大多数其他实现一起使用awk
mut_tmp[a][b]
和
mut_tmp[a,b]
这将起作用,因为进化枝编号和突变名称似乎不包含特殊字符\034
,默认情况下该特殊字符用于将各个组件连接到单字符串数组索引(查找SUBSEP
内部变量以获取更多信息)。
输入示例的输出是:
~$ awk -f compare.awk B.tsv A.tsv
id clade mutation missing_mutation remaining_mutation
243 40A siti,toto,mumu xixi,saxa siti
254
267 40B lala,sisi,sojo huhu sisi
请注意,您的示例所需的输出与您的需求描述不一致。
编辑
由于您在评论中指出,实际上A.tsv
进化枝位于第 22 列,突变位于第 41 列,因此请更改
split($3,mutations,/,/)
到split($41,mutations,/,/)
- 所有出现
n_tmp[$2]
的n_tmp[$22]
mut_tmp[$2][j]
(或[$2,j]
) 到mut_tmp[$22][j]
(或[$22,j]
, 分别出现)的所有出现
答案2
选择awk
:
awk 'BEGIN{ FS=OFS="\t" }
NR==FNR{ mutations[$1] =$2; next }
FNR>1 {
split($3, muts, "," );
for(x in muts) {
if (gsub( ",?"muts[x]",?", "", mutations[$2])>0) delete muts[x] }
}
FNR==1 { $4="missing_mutation"; $5="remaining_mutation" }
{ printf ("%s", $0 OFS mutations[$2] OFS );
for(r in muts) {
if(muts[r] ~/^[Ss]/) printf("%s", sep muts[r]); sep="," }
print ""; sep=""
}' fileB fileA