首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >匹配4列并替换1/2文件

匹配4列并替换1/2文件
EN

Unix & Linux用户
提问于 2019-08-15 10:58:14
回答 2查看 258关注 0票数 6

我有2个文件,文件1的第1列必须替换为文件2的第2列,第2、3、4-5或5-4列(交叉匹配)之后的第1栏必须替换为文件2的列1、4、5-6或6-5。

档案1

代码语言:javascript
运行
复制
SNP     Chr     Pos     EA      NEA     EAF     Beta    SE      Pvalue  Neff
1:79137     1       79137       A       T       0.25    -0.026  0.0073  4.0e-04 231420
1:79033      1       79033        A       G       0.0047  -0.038  0.056   4.9e-01 225429
1:118630     1       118630       C       T       0.99    -0.033  0.055   5.5e-01 226311
1:533179     1       533179       A       G       1       -0.098  0.19    6.1e-01 185906

档案2

代码语言:javascript
运行
复制
1       1:79033_A_G     0       79033   A       G
1       1:79137_A_T     0       79137   T       A
1       1:118630_C_T    0       118630  T       C
1       1:533179_A_G    0       533179  G       A

我需要输出如下所示:

代码语言:javascript
运行
复制
SNP     Chr     Pos     EA      NEA     EAF     Beta    SE      Pvalue  Neff
    1:79137_A_T     1       79137       A       T       0.25    -0.026  0.0073  4.0e-04 231420
    1:79033_A_G      1       79033        A       G       0.0047  -0.038  0.056   4.9e-01 225429
    1:118630_C_T     1       118630       C       T       0.99    -0.033  0.055   5.5e-01 226311
    1:533179_A_G     1       533179       A       G       1       -0.098  0.19    6.1e-01 185906

这些文件没有确切的行数,而且文件没有制表符分隔。我尝试了下面的代码,但它不起作用,你能纠正我的代码吗?

代码语言:javascript
运行
复制
awk 'NR==FNR{chr[$1]=$1;snp[$2]=$2;pos[$4]=$4;a1[$5]=$5;a2[$6]=$6;next} ($1 in chr)&&($4 in pos)&& ((($5 in a1) && ($6 in a2)) || (($6 in a1) && ($5 in a2))) {$2==snp[$2]}' file 2 file1

编辑1:

下面的perl代码犯了一些错误,并在大约20 000行中产生重复行,其中一个例子是,

档案1

代码语言:javascript
运行
复制
SNP     Chr     Pos     EA      NEA     EAF     Beta    SE      Pvalue  Neff
7:10100610      7       10100610        A       G       0.0002  0.13    0.58    8.2e-01 120658
7:10100610      7       10100610        C       G       0.0013  0.1     0.13    4.4e-01 139170
10:1006107      10      1006107 C       G       1       -0.11   0.42    7.9e-01 152016

档案2

代码语言:javascript
运行
复制
7       7:10100610_G_A  0       10100610        A       G
7       7:10100610_G_C  0       10100610        C       G
10      10:1006107_C_G  0       1006107 G       C

这些项目的预期产出:

代码语言:javascript
运行
复制
7:10100610_G_A      7       10100610        A       G       0.0002  0.13    0.58    8.2e-01 120658
7:10100610_G_C      7       10100610        C       G       0.0013  0.1     0.13    4.4e-01 139170
10:1006107_C_G      10      1006107 C       G       1       -0.11   0.42    7.9e-01 152016

但是perl代码提供的输出

代码语言:javascript
运行
复制
7:10100610_G_A  7       10100610        A       G       0.0002  0.13    0.58    8.2e-01 120658
10:1006107_C_G  7       10100610        C       G       0.0013  0.1     0.13    4.4e-01 139170
10:1006107_C_G  10      1006107 C       G       1       -0.11   0.42    7.9e-01 152016
EN

回答 2

Unix & Linux用户

回答已采纳

发布于 2019-08-15 12:10:52

join命令将完成从多个文件中连接匹配行的工作。但是它对其输入文件有一些要求,因此您需要在此过程中创建一些临时文件,并添加一些额外的字段。

代码语言:javascript
运行
复制
awk '{printf $2" "$3" "$4" "$5"%"$1"%"; $1="";print $0 "%" NR }' < file1 | sort > 1.tmp
awk '{print $1" "$4" "$5" "$6"%"$2} $5 != $6 {print $1" "$4" "$6" "$5"%"$2}' < file2 | sort > 2.tmp

join -a 1 -t % -o 1.4 2.2 1.2 1.3  1.tmp 2.tmp | sort -t % -n | awk -F %  '!$2{$2=$3}{print $2" "$4}'

一步

预处理第一个文件:

代码语言:javascript
运行
复制
awk '{printf $2" "$3" "$4" "$5"%"$1"%"; $1="";print $0 "%" NR }''

示例输出:

代码语言:javascript
运行
复制
1 118630 C T%1:118630% 1 118630 C T 0.99 -0.033 0.055 5.5e-01 226311%4

%分隔的这4个字段是:

  • 必须匹配的“键”(输入字段2-5)
  • 原始的第一列(在没有匹配的情况下需要)
  • 原行的其余部分
  • 原始行号(因此我们可以在sort之后恢复文件顺序)

这个输出通过sort管道传输到一个临时文件中,因为join需要对其输入进行排序。

对于第二个文件:

代码语言:javascript
运行
复制
awk '{print $1" "$4" "$5" "$6"%"$2} $5 != $6 {print $1" "$4" "$6" "$5"%"$2}'

示例输出:

代码语言:javascript
运行
复制
1 118630 C T%1:118630_C_T
1 118630 T C%1:118630_C_T

由于您指定字段5和6应该匹配,第二行将与它们交换(前提是它们不是相同的)。这里的%-separated字段是

  • 要匹配的“键”
  • 第2栏

同样,输出通过管道通过sort传输到另一个临时文件中。

然后是主要的“加入”步骤:

代码语言:javascript
运行
复制
join -a 1 -t % -o 1.4 2.2 1.2 1.3  1.tmp 2.tmp

当第一组中没有匹配时,-a 1指示join保留行。-t %将分隔符设置为% (而不是空格)。-o参数产生以下四个输出字段:

  • 文件1,第4列:行号
  • 文件2,第2列:从file2替换(当没有匹配时,这将是空的)
  • 文件1,第2列:来自file1的原始D43
  • 文件1,第3列:file1中行的其余部分

输出行示例:

代码语言:javascript
运行
复制
4%1:118630_C_T%1:118630% 1 118630 C T 0.99 -0.033 0.055 5.5e-01 226311

然后sort可以恢复原始文件顺序(数字排序,字段分隔符%)

代码语言:javascript
运行
复制
sort -t % -n

最后一个awk检查“替换”字段是否为空(因为没有找到匹配项),如果是,则使用原始的column1。它还丢弃了线号和所有的%s。

代码语言:javascript
运行
复制
awk -F % '!$2{$2=$3}{print $2" "$4}'

最后输出线:

代码语言:javascript
运行
复制
1:118630_C_T  1 118630 C T 0.99 -0.033 0.055 5.5e-01 226311
票数 6
EN

Unix & Linux用户

发布于 2019-08-15 12:22:46

我会在Perl中这样做,因为它有一个sort函数,可以让我们轻松地将A TT A视为相同的东西。例如(显示所有示例文件加在一起的输出):

代码语言:javascript
运行
复制
$ perl -lane 'if(!$k){$name{join("","chr".$F[0],$F[3],sort($F[4],$F[5]))}=$F[1]; }else{$var=join("", "chr".$F[1],$F[2],sort($F[3],$F[4])); $F[0]=$name{$var} if $name{$var};print join "\t", @F; } $k++ if eof' file2 file1
SNP Chr Pos EA  NEA EAF Beta    SE  Pvalue  Neff
7:10100610_G_A  7   10100610    A   G   0.0002  0.13    0.58    8.2e-01 120658
7:10100610_G_C  7   10100610    C   G   0.0013  0.1 0.13    4.4e-01 139170
10:1006107_C_G  10  1006107 C   G   1   -0.11   0.42    7.9e-01 152016
1:79137_A_T 1   79137   A   T   0.25    -0.026  0.0073  4.0e-04 231420
1:79033_A_G 1   79033   A   G   0.0047  -0.038  0.056   4.9e-01 225429
1:118630_C_T    1   118630  C   T   0.99    -0.033  0.055   5.5e-01 226311
1:533179_A_G    1   533179  A   G   1   -0.098  0.19    6.1e-01 185906

或者,稍微清楚一点:

代码语言:javascript
运行
复制
$ perl -lane 'if(!$k){
                $name{join("","chr".$F[0],$F[3],sort($F[4],$F[5]))}=$F[1]; 
              }
              else{
                $var=join("", "chr".$F[1],$F[2],sort($F[3],$F[4])); 
                $F[0]=$name{$var} if $name{$var};
                print join "\t", @F; 
             } 
            $k++ if eof' file2 file1
SNP Chr Pos EA  NEA EAF Beta    SE  Pvalue  Neff
7:10100610_G_A  7   10100610    A   G   0.0002  0.13    0.58    8.2e-01 120658
7:10100610_G_C  7   10100610    C   G   0.0013  0.1 0.13    4.4e-01 139170
10:1006107_C_G  10  1006107 C   G   1   -0.11   0.42    7.9e-01 152016
1:79137_A_T 1   79137   A   T   0.25    -0.026  0.0073  4.0e-04 231420
1:79033_A_G 1   79033   A   G   0.0047  -0.038  0.056   4.9e-01 225429

解释

  • perl -lane-a使perl像awk一样,自动将输入拆分为空格上的数组@F。由于perl数组从0开始,$F[0]将是第一个字段,$F[1]将是第二个字段,字段N是$F[N-1]-n使perl将其参数读入文本文件,并将-e给出的脚本应用于其中的每一行。-l只是从每个输入行中删除尾随的换行符,并向每个print调用添加一个换行符。
  • $k++ if eof:如果我们已经到达文件的末尾(eof),这会使变量$k增加1。然后,我们可以使用if(!$k) (如果没有定义$k )作为awk中的NR==FNR的等效值。
  • 如果(!$k){$name{连接(“”,"chr".$F,$F),排序( $F,TandT Aas equivalent. I use"chr".$Fto deal with cases like1 123and11 23‘),其中染色体和位置的连接给出了相同的数目,尽管染色体实际上是不同的。
  • else{:如果我们现在正在读取第二个文件,file1
  • $var=join("", $F[1],$F[2],sort($F[3],$F[4]));:构建密钥。这一次使用字段2、3和排序4和5。
  • $F[0]=$name{$var} if $name{$var};:如果存在此键的值,则将第一个字段设置为存储在name散列中的值。需要使用if来确保我们不会更改file1中可能出现的头或任何其他变体,但不会在file2中出现。
  • print join "\t", @F;:打印字段,包括上面所做的更改。
票数 5
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/535726

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档