Awk 在一个文件中查找等于零的值,然后用找到的值替换零值

Awk 在一个文件中查找等于零的值,然后用找到的值替换零值,awk,Awk,我有这样的数据: head out_sign.txt chr pos gene_id p.val.LCL p.val.Retina chr1 756164 ENSG00000237094 0 7.15853e-05 chr1 775930 ENSG00000237094 0 9.72251e-05 chr1 814583 ENSG00000237094 0 1.88553e-05 chr1 815963 ENSG00000237094 0 3.85837e-06 chr6 1

我有这样的数据:

head out_sign.txt
chr    pos    gene_id    p.val.LCL  p.val.Retina
chr1 756164 ENSG00000237094 0 7.15853e-05
chr1 775930 ENSG00000237094 0 9.72251e-05
chr1 814583 ENSG00000237094 0 1.88553e-05
chr1 815963 ENSG00000237094 0 3.85837e-06
chr6 130235069 ENSG00000164484 5.43098e-06 0
chr17 45848600 ENSG00000236234 9.005e-06 0
chr11 34862454 ENSG00000110435 1.81973e-06 0
chr17 45979467 ENSG00000236234 1.34927e-05 0
chr5 81234109 ENSG00000248794 4.36795e-06 0
{ sed '1d;s/^/L /' lcls.txt; sed '1d;s/^/R /' ret.txt; sed '1d;s/^/D /' out_sign.txt; } | 
   awk '
       /^L/ {lcls[$2,$3,$4]=$5; next}    # build "lcls" table
       /^R/ {ret[$2,$3,$4]=$5;  next}    # build "ret" table
       /^D/ {... per dash-o lines starting "if" but field numbers incremented ... }'
所以有时候p.val.LCL==0,有时候p.val.Retina==0

每次其中一个等于零时,我想在这两个文件中查找相应的组合:chr、pos、gene_id:

对于p.val.LCL==0,请在名为“lcls.txt”的文件中查找chr、pos、gene_id文件的组合,并用“lcls.txt”中找到的值替换零值

为了

p、 val.Retina==0在“ret.txt”文件中查找chr、pos、gene_id的组合,并用在“ret.txt”中找到的值替换零值

因此,对于这个给定的示例,解决方案是:

chr    pos      gene_id         p.val.LCL   p.val.Retina
chr1  756164    ENSG00000237094 0.1         7.15853e-05
chr1  775930    ENSG00000237094 0.4         9.72251e-05
chr1  814583    ENSG00000237094 0.6         1.88553e-05
chr1  815963    ENSG00000237094 0.7         3.85837e-06
chr6  130235069 ENSG00000164484 5.43098e-06 5.43098e-06
chr17 45848600  ENSG00000236234 9.005e-06   9.005e-06
chr11 34862454  ENSG00000110435 1.81973e-06 1.81973e-06
chr17 45979467  ENSG00000236234 1.34927e-05 1.34927e-05
chr5  81234109  ENSG00000248794 4.36795e-06 4.36795e-06
解决方案文件的行数与out_sign.txt相同

我应该提到,这些文件相当大,每个文件中的行数为:

107371529 ret.txt
166941636 lcls.txt
2250213 out_sign.txt
由于数据的大小,awk解决方案可能是最好的。
我尝试在R中执行此操作,但我遇到了与内存相关的错误。awk应该能够处理它。

可以使用awk脚本实现

awk '
t == "lcls" { if ( FNR > 1 ) lcls[$1, $2, $3] = $4 ; next }
t == "ret" { if ( FNR > 1 ) ret[$1, $2, $3] = $4 ; next }

        # Lookup for main file
{
        if ( $4 == 0 ) { v = lcls[$1, $2, $3] ; if ( v ) $4 = v ; }
        if ( $5 == 0 ) { v = ret[$1, $2, $3] ; if ( v ) $5 = v ; }
        print
}
' t=ret ret.txt t=lcls lcls.txt t= out_sign.txt

它将查找文件加载到awk表中,然后对“数据”文件执行替换。“t”变量表示输入的“类型”。

我认为@dash-o的方法可能更优雅。然而,为了好玩,这里有另一种类似a的方法,将三个输入文件区分为
awk
,去掉标题行,然后在每一行前面加上
L
R
D

因此,如果您使用:

sed '1d; s/^/L /' lcls.txt
sed '1d; s/^/R /' ret.txt
sed '1d; s/^/D /' out_sign.txt
您将得到以下结果:

L chr1 756164 ENSG00000237094 0.1
L chr1 775930 ENSG00000237094 0.4
L chr1 814583 ENSG00000237094 0.6
L chr1 815963 ENSG00000237094 0.7
R chr6 130235069 ENSG00000164484 5.43098e-06
R chr17 45848600 ENSG00000236234 9.005e-06 
R chr11 34862454 ENSG00000110435 1.81973e-06
R chr17 45979467 ENSG00000236234 1.34927e-05
R chr5 81234109 ENSG00000248794 4.36795e-06
D chr1 756164 ENSG00000237094 0 7.15853e-05
D chr1 775930 ENSG00000237094 0 9.72251e-05
D chr1 814583 ENSG00000237094 0 1.88553e-05
D chr1 815963 ENSG00000237094 0 3.85837e-06
D chr6 130235069 ENSG00000164484 5.43098e-06 0
D chr17 45848600 ENSG00000236234 9.005e-06 0
D chr11 34862454 ENSG00000110435 1.81973e-06 0
D chr17 45979467 ENSG00000236234 1.34927e-05 0
D chr5 81234109 ENSG00000248794 4.36795e-06 0
现在您可以像这样
awk

head out_sign.txt
chr    pos    gene_id    p.val.LCL  p.val.Retina
chr1 756164 ENSG00000237094 0 7.15853e-05
chr1 775930 ENSG00000237094 0 9.72251e-05
chr1 814583 ENSG00000237094 0 1.88553e-05
chr1 815963 ENSG00000237094 0 3.85837e-06
chr6 130235069 ENSG00000164484 5.43098e-06 0
chr17 45848600 ENSG00000236234 9.005e-06 0
chr11 34862454 ENSG00000110435 1.81973e-06 0
chr17 45979467 ENSG00000236234 1.34927e-05 0
chr5 81234109 ENSG00000248794 4.36795e-06 0
{ sed '1d;s/^/L /' lcls.txt; sed '1d;s/^/R /' ret.txt; sed '1d;s/^/D /' out_sign.txt; } | 
   awk '
       /^L/ {lcls[$2,$3,$4]=$5; next}    # build "lcls" table
       /^R/ {ret[$2,$3,$4]=$5;  next}    # build "ret" table
       /^D/ {... per dash-o lines starting "if" but field numbers incremented ... }'
或者,如果您喜欢
bash
流程替换,则这相当于:

awk '...' <(sed '1d; s/^/L /' lcls.txt) <(sed '1d; s/^/R /' ret.txt) <(sed '1d; s/^/D /' out_sign.txt)

awk'…'您也可以这样做:
awk'{print p,$0}'p=L lcls.txt p=R ret.txt p=D out\u sign.txt
这并没有给我所需的输出,请参阅我的帖子,那里是解决方案。有了这个代码,我得到了:L chr pos gene_id pval_nominal L chr1 13550 ensg000027232 0。375614@MarkSetchell我尝试了你的awk命令,我得到了这个错误:awk:cmd。行:1:。。。awk:cmd。第1行:^语法错误嗨,非常感谢你回复我。我尝试了你的代码,重定向了输出,比如:lcls.txt t=out\u sign.txt>res\u tpr.txt,在这个输出文件中我得到了:rchropsgene\u id=pval\u ret rchr10177ensg000027232=0.381708 rchr10352ensg000027232=0.9523 rchr11008ensg000027232=0.218132I需要我在帖子中指定的输出。结果是,使用awk命令生成的代码有276563378行我已经删除了调试打印输出'Rchr…'和'Lchr…'非常感谢这太棒了!