如果一列中的值包含连续数字并且所有其他列匹配,如何合并行

How to merge rows if values in one column contains consective numbers and all other columns match

我有一个非常大的文件(约 7 亿行),我想通过对大部分匹配的行进行分组来减小大小。具体来说,该文件按字段 1 和 2 排序,我想对字段 2 包含连续数字但所有其他字段匹配的行进行分组。如果字段 2 中存在空白,或者如果任何其他字段与前一行不匹配,那么我想开始一个新的间隔。理想情况下,我希望输出 return 分组行的间隔范围,并且更喜欢使用 awk and/or sed 在 bash 中工作的解决方案。我对其他解决方案持开放态度,只要它们不需要重新排序或其他可能因如此长的文件而崩溃的操作。

输入文件看起来像这样。

NW_005179401.1  100 1   0   0   0   0   0   0   0   0
NW_005179401.1  101 1   0   0   0   0   0   0   0   0
NW_005179401.1  102 1   0   0   0   0   0   0   0   0
NW_005179401.1  103 1   0   0   0   0   0   1   0   0
NW_005179401.1  104 1   0   0   0   0   0   1   0   0
NW_005179401.1  105 1   0   0   0   0   0   1   0   0
NW_005179401.1  106 1   0   0   0   0   0   1   0   0
NW_005179401.1  108 1   0   0   0   0   0   1   0   0
NW_005179401.1  109 1   0   0   0   0   0   1   0   0
NW_005179401.1  110 1   0   0   0   0   0   1   0   0
NW_005179401.1  111 1   0   0   0   0   0   1   0   0
NW_005179401.1  112 1   0   0   0   0   0   1   0   0
NW_005179401.1  992 0   0   1   1   0   0   0   0   2
NW_005179401.1  993 0   0   1   1   0   0   0   0   2
NW_005179401.1  994 0   0   1   1   0   0   0   0   2
NW_005179401.1  995 0   0   1   1   0   0   0   0   2
NW_005179401.1  996 0   0   1   1   0   0   0   0   0
NW_005179401.1  997 0   0   1   1   0   0   0   0   0
NW_005179401.1  998 0   0   1   1   0   0   0   0   0
NW_005179401.1  999 0   0   1   1   0   0   0   0   0

实际上,该文件有更多字段,但都包含整数,例如示例中的字段 3 及以后的字段。理想的输出将如下所示,连续字段 2 间隔中的第一个和最后一个值打印在输出字段 2 和 3 中。

NW_005179401.1  100 102 1   0   0   0   0   0   0   0   0
NW_005179401.1  103 106 1   0   0   0   0   0   1   0   0
NW_005179401.1  108 112 1   0   0   0   0   0   1   0   0
NW_005179401.1  992 995 0   0   1   1   0   0   0   0   2
NW_005179401.1  996 999 0   0   1   1   0   0   0   0   0

我发现解决方案将连续行与特定字段中的匹配项分组,但 none 也在一个字段中查找连续整数,而不是可以 return 范围的整数。一种想法是在跳过前 2 个字段的同时使用带有 -c 标志的 uniq,然后将计数添加到字段 2 中的值,但是考虑到在字段 2 中需要连续数字的附加条件我不太确定从哪里开始这个。提前致谢。

编辑:我为最初没有添加我尝试的代码而道歉,但我的管道使用了生物信息学程序 bedtools 并且它由于内存不足而不断被杀死,这不是我预期的由于缺乏预编程功能。我是 awk 新手,不知道从哪里开始寻找重新格式化此类文件的替代管道。

我怀疑是否有像 uniq -c 这样的标准工具。但是您可以使用这个自定义 awk 脚本:

awk '{=} [=10=]!=n {s=; printf "%s", g}
{=+1; n=[=10=]; =s" "-1; g=[=10=] ORS}
END {printf "%s", g}' yourFile
  • n下一个预期的记录,
    例如如果当前行是 abc 100 x y z 那么 n=abc 101 x y z.
  • g 是要打印的 记录,以防下一个预期行 n 没有出现并且该组结束。
  • sstart组数g,即区间的下界。
  • {=}只是为了确保当前行[=23=]和生成的行n中的字段分隔符是一致的,这样我们就可以使用[=25来检查相等性=],在这种情况下更确切地说是 !=

对于您的示例,这将打印

NW_005179401.1 100 102 1 0 0 0 0 0 0 0 0
NW_005179401.1 103 106 1 0 0 0 0 0 1 0 0
NW_005179401.1 108 112 1 0 0 0 0 0 1 0 0
NW_005179401.1 992 995 0 0 1 1 0 0 0 0 2
NW_005179401.1 996 999 0 0 1 1 0 0 0 0 0
$ cat tst.awk
{
    prevVals = currVals
    origRec = [=10=]
     = ""
    currVals = [=10=]
    [=10=] = origRec
}
( != endKey+1) || (currVals != prevVals) {
    if ( NR>1 ) {
        prt()
    }
    begKey = 
}
{ endKey =  }
END { prt() }

function prt(   origRec) {
    origRec = [=10=]
     = begKey OFS endKey
    print
    [=10=] = origRec
}

$ awk -f tst.awk file
NW_005179401.1 100 102 1 0 0 0 0 0 1 0 0
NW_005179401.1 103 106 1 0 0 0 0 0 1 0 0
NW_005179401.1 108 112 0 0 1 1 0 0 0 0 2
NW_005179401.1 992 995 0 0 1 1 0 0 0 0 0
NW_005179401.1 996 999 0 0 1 1 0 0 0 0 0