【问题标题】:awk to find overlapsawk 查找重叠
【发布时间】:2014-01-31 19:39:31
【问题描述】:

我有一个包含如下所示列的文件。

Group   Start        End
chr1    117132092    118875009
chr1    117027758    119458215
chr1    103756473    104864582
chr1    105093795    106219211
chr1    103354114    104747251
chr1    102741437    105235140
chr1    100090254    101094139
chr1    100426977    101614730
chr2    86644663     87767193
chr2    82473711     83636545
chr2    83896702     85079032
chr2    83876122     85091910
chr2    82943211     84350917
chr3    89410051     90485635
chr3    89405753     90485635
chr3    86491492     87593215
chr3    82507157     83738004
chr3    85059618     86362254

我想找到每组中这些坐标之间的重叠(按 chr1、chr2、chr3.. 分组)。

如果与同一组中的其他人至少有 50% 的重叠,则必须检查开始和结束坐标。如果至少有 50% 的重叠,则必须在第 3 列和第 4 列(这是重叠区域的范围)中报告新的开始和结束坐标。如果它们不重叠,则必须在第 3 列和第 4 列中报告原始开始和结束。

为了更清楚,让我们取前两行

                 117132092..........118875009
         117027758...........................119458215

由于它们彼此重叠至少 50%,因此重叠的范围在输出中报告为新开始和新结束。并且第 3 行和第 4 行不与其他行重叠,因此原始坐标在第 3 列和第 4 列中报告为新起点和新终点。同样,由于第 5 行和第 6 行彼此重叠 50%,因此它们的范围报告为新坐标第 3 列和第 4 列中的开始和新结束。 这是预期的输出:

Group   Start     End         NewStart   NewEnd   
chr1 117132092 118875009  117027758   119458215
chr1 117027758 119458215  117027758   119458215
chr1 103756473 104864582  103354114   104864582
chr1 105093795 106219211  105093795   106219211
chr1 103354114 104747251  102741437   105235140
chr1 102741437 105235140  102741437   105235140
chr1 100090254 101094139  100090254   101614730
chr1 100426977 101614730  100090254   101614730
chr2 86644663 87767193    86644663    87767193
chr2 82473711 83636545    82473711    83636545 
chr2 83896702 85079032    83876122    85091910
chr2 83876122 85091910    83876122    85091910
chr2 82943211 84350917    82943211    84350917
chr3 89410051 90485635    89405753    90485635
chr3 89405753 90485635    89405753    90485635
chr3 86491492 87593215    86491492    87593215
chr3 82507157 83738004    82507157    83738004
chr3 85059618 86362254    85059618    86362254

我已经用 R 编程语言实现了这一点,但是原始文件太大并且需要很长时间才能运行。有人可以帮助在 awk 中做到这一点。

【问题讨论】:

  • 或许您可以使用较小的数字来减少读者的压力?
  • 例如,以下(start,end)s 将如何映射到同一组中? (1,4), (2,3), (1,2), (3,6), (2,5), (5,7) 当重叠超过 50% 时,最大的重叠是否“获胜”?如果有多个重叠或一个重叠等于另一个,您要报告高范围还是低范围?
  • @MiserableVariable 我在示例中使用了相同的数字
  • 有趣的问题,但这是相当数量的免费劳动力。你试过什么?
  • 我认为@MiserableVariable 和 n0741337 的重点是使用较小的数字(最多 3 位?,或者至少是问题的最小数字)重写您的问题。您的问题中使用的数字为可能更简单(比看起来)的问题增加了相当大的认知压力。祝你好运。

标签: awk overlap


【解决方案1】:

使用 Gnu Awk 版本 4,您可以尝试:

gawk -f a.awk file file

a.awk 在哪里:

NR==FNR {
    if (FNR>1) {
        a[$1][++i]=$2
        b[$1][i]=$3
    }
    next
}
FNR==1 {
    fmt="%-7s%-10s%-10s%-10s%-10s\n"
    printf fmt,"Group","Start","End","NewStart","NewEnd" 
}
FNR>1{
    $4=$2; $5=$3
    n=checkInside($1,$2,$3)
    if (n>0) {
        ff=0; x=$2; y=$3
        for (i=1; i<=n; i++) {
            ar=a[$1][R[i]]; br=b[$1][R[i]];
            getIntersect($2,$3,ar,br)
            getLargest($2,$3,ar,br)
            ovl=((i2-i1)/($3-$2))*100;
            ovr=((i2-i1)/(br-ar))*100;
            if (ovl>50 && ovr>50) {
                if (r1<x) x=r1
                if (r2>y) y=r2
                ff=1
            }
        }
        if (ff) {
            $4=x; $5=y
        }
    }
    printf fmt,$1,$2,$3,$4,$5
}

function getLargest(x1,y1,x2,y2) {
    r1=(x1<=x2)?x1:x2
    r2=(y1>=y2)?y1:y2
}

function getIntersect(x1,y1,x2,y2) {
    if (x1>=x2 && x1<=y2) {
        i1=x1;
    } else {
        i1=x2;
    }
    i2=(y1<=y2)?y1:y2
}

function checkInside(g,x,y,i,j,x1,y1) {
    R["x"]=0
    for (i in a[g]) {
        x1=a[g][i]; y1=b[g][i];
        if ((x>=x1 && x<=y1) || (y>=x1 && y<=y1)) {
            if (!(x==x1 && y==y1))
                R[++j]=i
        }
    }
    return j
}

输出:

Group  Start     End       NewStart  NewEnd    
chr1   117132092 118875009 117027758 119458215 
chr1   117027758 119458215 117027758 119458215 
chr1   103756473 104864582 103354114 104864582 
chr1   105093795 106219211 105093795 106219211 
chr1   103354114 104747251 102741437 105235140 
chr1   102741437 105235140 102741437 105235140 
chr1   100090254 101094139 100090254 101614730 
chr1   100426977 101614730 100090254 101614730 
chr2   86644663  87767193  86644663  87767193  
chr2   82473711  83636545  82473711  83636545  
chr2   83896702  85079032  83876122  85091910  
chr2   83876122  85091910  83876122  85091910  
chr2   82943211  84350917  82943211  84350917  
chr3   89410051  90485635  89405753  90485635  
chr3   89405753  90485635  89405753  90485635  
chr3   86491492  87593215  86491492  87593215  
chr3   82507157  83738004  82507157  83738004  
chr3   85059618  86362254  85059618  86362254  

【讨论】:

  • @user1779730 好的,希望你有 Gnu Awk 版本 4 :) 你不能按照你的建议替换 printf。在你的建议中,printf 将只收到 3 个参数,但 fmt 字符串需要 5 个参数..
  • 我有一个小问题。如果您查看第 5 行,它与第 3 行和第 6 行重叠,第 5 行的新起点应该是 102741437,因为它是第 3,5 和 6 行中起点的最小值,新终点应该是 105235140,因为它是最大值在第 3,5 和 6 行结束。
  • @user1779730 我得考虑一下 :)
  • @user1779730 所以如果有N 重叠,它应该考虑所有这些,而不仅仅是重叠百分比最大的那个?
  • @user1779730 如果 2 个重叠大于 50% 而 2 个小于 50% 怎么办?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-05
  • 2016-06-09
  • 2014-09-15
  • 1970-01-01
  • 2017-12-23
  • 2016-07-23
  • 2022-01-10
相关资源
最近更新 更多