筛选文件以查找在某一列中匹配但在另一列中不同的行

时间:2018-07-10 08:32:30

标签: awk samtools

我想过滤文件,以便获得与第1列匹配但与第2列不匹配的行。在以下示例中:

00b27c71-a833-4605-9fb3-a2714ac98092    ENST00000352983.6   157 60  16
00d77e65-466e-4fe6-ad0f-bc6b3f44af75    ENST00000367142.4   130 12  4
00d77e65-466e-4fe6-ad0f-bc6b3f44af75    ENST00000367142.4   8   60 0
00b27c71-a833-4605-9fb3-a2714ac98091    ENST00000258424.2   12  60 2048
00b27c71-a833-4605-9fb3-a2714ac98091    ENST00000352983.6   157 60  16
00d77e65-466e-4fe6-ad0f-bc6b3f44af74    ENST00000367142.5   130 12  4
00d77e65-466e-4fe6-ad0f-bc6b3f44af74    ENST00000367142.7   8   60 0
00d77e65-466e-4fe6-ad0f-bc6b3f44af74    ENST00000258424.2   8   60 0

我想在第1列中找到恰好出现两次但在第2列中不匹配的整体,即,应该忽略组合column1,column2中的重复项。因此,预期输出为:

00b27c71-a833-4605-9fb3-a2714ac98091    ENST00000258424.2   12  60 2048
00b27c71-a833-4605-9fb3-a2714ac98091    ENST00000352983.6   157 60  16

第3、4、5等栏中的内容对于过滤并不重要,但我确实需要保留信息。

我还需要从另一个输出中将其通过管道传递,这对于读取文件和保留标题是必需的。所以我需要以下格式的东西:

samtools view -h file.bam | code that I need > results.bam

我尝试了几种版本的awk,但无济于事。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

编辑: :根据OP,它应该是从awk读取的单次读入,因此不能添加。w

your_command |  awk '
{
  a[$1]++;
  b[$1 FS $2]++;
  c[$1 FS $2]=$0
}
END{
  for(i in a){
    for(j in b){
      split(j,array," ");
      if(a[i]==2 && b[j]==1 && i==array[1]){  print c[j]  }
    }
}}'

能否请您尝试以下操作,如果有帮助,请告诉我。

awk 'FNR==NR{a[$1]++;b[$1 FS $2]++;next} a[$1]==2 && b[$1 FS $2]==1'  Input_file  Input_file

答案 1 :(得分:1)

我相信您的追求如下:

awk '!($1 FS $2 in a) { b[$1]++; a[$1 FS $2]=$0 }
     END { for(i in a) {$0=i; if (b[$1]==2) print a[i] } }' file

这将输出:

00b27c71-a833-4605-9fb3-a2714ac98091    ENST00000352983.6   157 60  16
00b27c71-a833-4605-9fb3-a2714ac98091    ENST00000258424.2   12  60 2048

它的主要作用是检查组合$1 FS $2是否在数组a中。如果不是,请跟踪$1b[$1]的计数,并将整行存储在a[$1 FS $2]中。最后,如果计数正确,请打印a[i]。请注意,b的密钥是通过将密钥i重新分配给$0获得的。这将重新定义字段$1$2,而$1是您想要的键。

注意:由于数组遍历以未指定的顺序进行,因此上述脚本不一定跟踪该顺序。如果要保留订单,则需要跟踪行索引:

awk '!($1 FS $2 in a) { b[$1]++; a[$1 FS $2]=$0; c[NR]=$1 FS $2 }
     END { for(i=1;i<=NR;++i) if(i in c) { $0=c[i]; if (b[$1]==2) print a[$0]}
     }' file

输出:

00b27c71-a833-4605-9fb3-a2714ac98091    ENST00000258424.2   12  60 2048
00b27c71-a833-4605-9fb3-a2714ac98091    ENST00000352983.6   157 60  16

旧答案:

awk '!($1 in a) { a[$1]=$2; b[$1]=$0; next }
     !match($2,a[$1]){a[$1]=a[$1] FS $2; b[$1]=b[$1] ORS $0}
     END { for (i in a) if (gsub(FS,FS,a[i]) == 1) print b[i] }' file

这将输出:

00b27c71-a833-4605-9fb3-a2714ac98091    ENST00000258424.2   12  60 2048
00b27c71-a833-4605-9fb3-a2714ac98091    ENST00000352983.6   157 60  16

它本质上的作用是跟踪两个都由第一列索引的数组(ab)。如果数组a不包含列$2的元素,则它将其添加到字符串a[$1]中。它还将完整行存储在b[$1]中,并以ORS分隔。 最后,我们计算a[i]中有多少个字段,如果为两个,则打印b[i]