我有2个文件,文件1的第1列必须替换为文件2的第2列,第2、3、4-5或5-4列(交叉匹配)之后的第1栏必须替换为文件2的列1、4、5-6或6-5。
档案1
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
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我需要输出如下所示:
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这些文件没有确切的行数,而且文件没有制表符分隔。我尝试了下面的代码,但它不起作用,你能纠正我的代码吗?
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
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
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这些项目的预期产出:
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代码提供的输出
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发布于 2019-08-15 12:10:52
join命令将完成从多个文件中连接匹配行的工作。但是它对其输入文件有一些要求,因此您需要在此过程中创建一些临时文件,并添加一些额外的字段。
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}'预处理第一个文件:
awk '{printf $2" "$3" "$4" "$5"%"$1"%"; $1="";print $0 "%" NR }''示例输出:
1 118630 C T%1:118630% 1 118630 C T 0.99 -0.033 0.055 5.5e-01 226311%4由%分隔的这4个字段是:
sort之后恢复文件顺序)这个输出通过sort管道传输到一个临时文件中,因为join需要对其输入进行排序。
对于第二个文件:
awk '{print $1" "$4" "$5" "$6"%"$2} $5 != $6 {print $1" "$4" "$6" "$5"%"$2}'示例输出:
1 118630 C T%1:118630_C_T
1 118630 T C%1:118630_C_T由于您指定字段5和6应该匹配,第二行将与它们交换(前提是它们不是相同的)。这里的%-separated字段是
同样,输出通过管道通过sort传输到另一个临时文件中。
然后是主要的“加入”步骤:
join -a 1 -t % -o 1.4 2.2 1.2 1.3 1.tmp 2.tmp当第一组中没有匹配时,-a 1指示join保留行。-t %将分隔符设置为% (而不是空格)。-o参数产生以下四个输出字段:
file2替换(当没有匹配时,这将是空的)file1的原始D43file1中行的其余部分输出行示例:
4%1:118630_C_T%1:118630% 1 118630 C T 0.99 -0.033 0.055 5.5e-01 226311然后sort可以恢复原始文件顺序(数字排序,字段分隔符%)
sort -t % -n最后一个awk检查“替换”字段是否为空(因为没有找到匹配项),如果是,则使用原始的column1。它还丢弃了线号和所有的%s。
awk -F % '!$2{$2=$3}{print $2" "$4}'最后输出线:
1:118630_C_T 1 118630 C T 0.99 -0.033 0.055 5.5e-01 226311发布于 2019-08-15 12:22:46
我会在Perl中这样做,因为它有一个sort函数,可以让我们轻松地将A T和T A视为相同的东西。例如(显示所有示例文件加在一起的输出):
$ 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或者,稍微清楚一点:
$ 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 225429perl -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的等效值。andT 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;:打印字段,包括上面所做的更改。https://unix.stackexchange.com/questions/535726
复制相似问题