一组重复行的总和,如果不重复则加 1 并计算差值

Sum of a block of duplicated rows, if not duplicated add 1 and calculate difference

我需要解析几个具有以下结构的排序文件:

1_0.91  10
1_0.91  20
1_0.91  30
1_0.91  40
2_0.89  50
1_0.91  60
1_0.91  70
1_0.91  80
2_0.89  90
2_0.89  100
2_0.89  110
3_0.86  120

第一列是基因组中的特征,第二列是它们的位置。每个特征都与其他特征间隔开。我想找到每个功能的大小或每个功能的块。对于这个例子,我想要的输出如下:

1_0.91  10  40  30
2_0.89  50  51  1
1_0.91  60  80  20
2_0.89  90  110 20
3_0.86  120 121 1

要素 1_0.91 从 10 开始,位于位置 20、30 和 40。我想创建一个包含开始和结束的新列。在本例中,从 10 开始到 40 结束。然后在新列中输出它们的大小(结束减去开始,在本例中为 30)。有几个地方我每个功能只有一次。在我的示例中,2_0.89 位于特征块 1_0.91 之间。在这种情况下,我想将 1 添加到当前值并估计大小,在这种情况下,等于 1。

我尝试过使用 awk,但我对只出现一次的功能感到困惑。

这是我目前使用的。有点绕: 让我们调用第一个文件 file1.txt:

cat file1.txt | awk '!=prev{if (pline){print pline;}print;}{prev=;pline=[=12=];}END{print pline;}' > file2.txt

输出:

1_0.91  10
1_0.91  40
2_0.89  50
2_0.89  50
1_0.91  60
1_0.91  80
2_0.89  90
2_0.89  110
3_0.86  120
3_0.86  120

现在,我使用 sed 打印奇数行和偶数行,然后使用粘贴将文件放在一起:

paste <(cat file2.txt | sed 'n; d') <(cat file2.txt | sed '1d; n; d' ) | awk 'BEGIN{OFS="\t"} {print ,,}' > file3.txt

输出:

1_0.91  10  40
2_0.89  50  50
1_0.91  60  80
2_0.89  90  110
3_0.86  120 120

接下来,我估算每个特征的大小:

cat file3.txt | awk 'BEGIN{OFS="\t"} {print ,,,-}' > file4.txt

输出:

1_0.91  10  40  30
2_0.89  50  50  0
1_0.91  60  80  20
2_0.89  90  110 20
3_0.86  120 120 0

接下来,我用 1 替换第 4 列中的零:

cat file4.txt | awk 'BEGIN{OFS="\t"} {  = ( == "0" ? 1 : ) } 1' > file5.txt

输出:

1_0.91  10  40  30
2_0.89  50  50  1
1_0.91  60  80  20
2_0.89  90  110 20
3_0.86  120 120 1

最后,我用awk修复了每个特性的结尾:

cat file5.txt | awk 'BEGIN{OFS="\t"} {  = ( ==  ? +1 : ) } 1' > file6.txt

输出:

1_0.91  10  40  30
2_0.89  50  51  1
1_0.91  60  80  20
2_0.89  90  110 20
3_0.86  120 121 1

我想知道是否有更快更简单的方法来做到这一点。 谢谢。

假设:

  • 具有相同特征(字段#1)的连续行按位置(字段#2)升序排序
  • input/output 字段分隔符是 \t
  • 位置(字段 #2)值始终为正整数(否则我们可以调整代码)

一个awk想法:

awk '
function print_feature() {
    if ( feature != "" )
       print feature,min,max,(max-min)
}

BEGIN         { FS=OFS="\t" }
 != feature { print_feature()          # row contains a new/different feature, so print previous feature details
                feature=
                min=
                max=min+1
                next
              }
              { max= }                 # row contains a repeated/duplicate feature
END           { print_feature() }        # flush last feature details to stdout
' feature.dat

这会生成:

1_0.91  10      40      30
2_0.89  50      51      1
1_0.91  60      80      20
2_0.89  90      110     20
3_0.86  120     121     1