使用 awk、sed 或 R 基于字符串模式复杂提取所有行条目

Complex extract of all row entries based on string pattern using awk, sed or R

我有一个这样的 7 列文件:

ID ANNOTATION OR PVAL VAR_INFO INFO_TAGS_USED_TO_ANNOTATE INFO_TAGS_USED_TO_ANNOTATE
1 ANN1 1.66 0.0028 1:154837796(1.12e-06,0) 1:154834092(1.49e-05,0)|1:154834911(1.2e-05,1)| 1:155008318(0.000201,0)|1:155008973(0.000177,0)|
1 ANN1 1.66 0.0028 3:53707953(1.21e-06,0) 3:53708850(1.68e-06,1)|3:53711735(8.52e-07,1)| |3:53765419(0.0021,0)|
1 ANN1 1.66 0.0028 12:109966662(6.723e-06,0) 12:109888779(3.01e-05,0)|12:109889704(5.242e-05,0)|12:109890955(4.79e-05,0)| 12:110105520(NA,0)|12:110132792(0.00015,0)|12:110155571(3.93e-05,0)|

我正在尝试使用 grep、sed、awk 或 R 找到解决方案。我需要从 space 分隔的文本文件中提取第 6 列中的所有实例(INFO_TAGS_USED_TO_ANNOTATE column)其中值 1 出现在逗号之后。

每当出现 1 时,我需要为每个实例保留的信息是,以第 1 行为例,1:154834911(1.2e-05,1)。此信息对应于 SNP 信息,即 chromosome number:base position(p-value,annotation=1).

如果在特定行中出现多个 1 实例,那么我需要每个实例,并报告相应的 SNP 信息。因此,以第 2 行为例,将报告两个实例 3:53708850(1.68e-06,1)|3:53711735(8.52e-07,1).

如果可能,每行的提取信息将附加到新列中。

第 6 列中的每个条目由 | 分隔。如果为特定行报告了多个条目,则使用 | 作为新列中的分隔符会很有用。

上述输出的最后一列的输出如下所示

NewCol
1 1:154834911(1.2e-05,1)
2 3:53708850(1.68e-06,1)|3:53711735(8.52e-07,1)
3 <empty>

请注意,第 5、6 和 7 列中的信息非常相似,可能会造成混淆。

如有任何建议,我们将不胜感激。

perl 在这里工作得很好:

perl -lane '
    if ($. == 1) {
        $val = "NewCol";
    } else {
        $val = join "|", grep {/,1\)/} split /\|/, $F[5];
    }
    print join " ", @F, $val;
' file
ID ANNOTATION OR PVAL VAR_INFO INFO_TAGS_USED_TO_ANNOTATE INFO_TAGS_USED_TO_ANNOTATE NewCol
1 ANN1 1.66 0.0028 1:154837796(1.12e-06,0) 1:154834092(1.49e-05,0)|1:154834911(1.2e-05,1)| 1:155008318(0.000201,0)|1:155008973(0.000177,0)| 1:154834911(1.2e-05,1)
1 ANN1 1.66 0.0028 3:53707953(1.21e-06,0) 3:53708850(1.68e-06,1)|3:53711735(8.52e-07,1)| |3:53765419(0.0021,0)| 3:53708850(1.68e-06,1)|3:53711735(8.52e-07,1)
1 ANN1 1.66 0.0028 12:109966662(6.723e-06,0) 12:109888779(3.01e-05,0)|12:109889704(5.242e-05,0)|12:109890955(4.79e-05,0)| 12:110105520(NA,0)|12:110132792(0.00015,0)|12:110155571(3.93e-05,0)|

这就是魔法:$val = join "|", grep {/,1\)/} split /\|/, $F[5]; -- 你必须从右到左阅读:

  • 首先使用竖线(这是一个特殊的正则表达式字符,因此需要小心)拆分第 6 个字段(perl 使用基于 0 的索引),
  • 然后只保留逗号后和右括号前带“1”的位,
  • 然后用管道连接剩余的位。

如果你想惹恼你的同事,这可以降低到

perl -lape '$_=join" ",@F,$.==1?"NewCol":join"|",grep{/,1\)/}split/[|]/,$F[5]' file

使用 R 读取 myfile 中的注释行,然后使用 gsub 删除不需要的部分,将剩下的部分放入新列中。使用的数据在最后显示。

library(gsubfn)
# DF <- read.table("myfile", header = TRUE, as.is = TRUE, 
#   check.names = FALSE, strip.white = TRUE)
DF <- read.table(text = Lines, header = TRUE, as.is = TRUE, 
  check.names = FALSE, strip.white = TRUE)

transform(DF, NEWCOL = gsub("([^,]+),[^1]\)\|", "", INFO_TAGS_USED_TO_ANNOTATE))

备注

Lines <- "
ID ANNOTATION OR PVAL VAR_INFO INFO_TAGS_USED_TO_ANNOTATE INFO_TAGS_USED_TO_ANNOTATE
1 ANN1 1.66 0.0028 1:154837796(1.12e-06,0) 1:154834092(1.49e-05,0)|1:154834911(1.2e-05,1)| 1:155008318(0.000201,0)|1:155008973(0.000177,0)|
1 ANN1 1.66 0.0028 3:53707953(1.21e-06,0) 3:53708850(1.68e-06,1)|3:53711735(8.52e-07,1)| |3:53765419(0.0021,0)|
1 ANN1 1.66 0.0028 12:109966662(6.723e-06,0) 12:109888779(3.01e-05,0)|12:109889704(5.242e-05,0)|12:109890955(4.79e-05,0)| 12:110105520(NA,0)|12:110132792(0.00015,0)|12:110155571(3.93e-05,0)|
"

在每个 UNIX 机器上的任何 shell 中使用任何 awk:

$ cat tst.awk
NR==1 { print [=10=], "NewCol"; next }
{
    new = sep = ""
    n = split(,f,/[|]/)
    for (i=1; i<=n; i++) {
        if ( f[i] ~ /,1/ ) {
            new = new sep f[i]
            sep = "|"
        }
    }
    print [=10=], new
}

$ awk -f tst.awk file
ID ANNOTATION OR PVAL VAR_INFO INFO_TAGS_USED_TO_ANNOTATE INFO_TAGS_USED_TO_ANNOTATE NewCol
1 ANN1 1.66 0.0028 1:154837796(1.12e-06,0) 1:154834092(1.49e-05,0)|1:154834911(1.2e-05,1)| 1:155008318(0.000201,0)|1:155008973(0.000177,0)| 1:154834911(1.2e-05,1)
1 ANN1 1.66 0.0028 3:53707953(1.21e-06,0) 3:53708850(1.68e-06,1)|3:53711735(8.52e-07,1)| |3:53765419(0.0021,0)| 3:53708850(1.68e-06,1)|3:53711735(8.52e-07,1)
1 ANN1 1.66 0.0028 12:109966662(6.723e-06,0) 12:109888779(3.01e-05,0)|12:109889704(5.242e-05,0)|12:109890955(4.79e-05,0)| 12:110105520(NA,0)|12:110132792(0.00015,0)|12:110155571(3.93e-05,0)|

这可能对你有用 (GNU sed):r

sed -E 'h;s/\S+/\n&\n/6;s/.*\n(.*)\n.*//;s/[^,]+,([^1)]|[^)]{2,})\|//g;s/\|$//;1s/.*/newcol/;H;g;s/\n/ /' file

复制该行,隔离第 6 个字段,删除逗号后不包含 1 的字符串,删除最后的 | 并将结果附加到原始行。