如何使用bash替换一个文件中基于另一个文件中两列的多列值?
我正在尝试使用awk替换文件中多列的值。使用awk的原因是文件非常大,无法将其加载到内存中。我试着和熊猫(蟒蛇)打交道 我有一个作为文本文件的大型数据库。我在这里放了一个文件中信息的示例(以制表符分隔): 如果前两列(CHROM,POS)在行中相同,我必须对标题中包含“_00”的列的值求和 因此,预期输出为:如何使用bash替换一个文件中基于另一个文件中两列的多列值?,bash,awk,Bash,Awk,我正在尝试使用awk替换文件中多列的值。使用awk的原因是文件非常大,无法将其加载到内存中。我试着和熊猫(蟒蛇)打交道 我有一个作为文本文件的大型数据库。我在这里放了一个文件中信息的示例(以制表符分隔): 如果前两列(CHROM,POS)在行中相同,我必须对标题中包含“_00”的列的值求和 因此,预期输出为: CHROM POS REF ALT GT_00 d_GT_00 c_GT_00 de_GT_00 can_GT_00 epi_GT_00 chr1
CHROM POS REF ALT GT_00 d_GT_00 c_GT_00 de_GT_00 can_GT_00 epi_GT_00
chr1 10 T A 21 4 3 6 13 10
chr1 10 T A 21 4 3 6 13 10
chr1 10 T G 21 4 3 6 13 10
chr1 11 None None 4 1 0 0 7 7
chr1 11 G T 4 1 0 0 7 7
我不知道该怎么做,因为我对编程非常陌生,所以,我必须用这个awk
代码做下面的事情
awk -F'\t' 'FNR==1{next};
{keys[$1"\t"$2]
for (i=5;i<=10;i++)
{sum[$1"\t"$2, i] += $i}
}END {for (key in keys) { printf "%s", key
for (i=5;i<=10;i++) {printf "%s%s", "\t", sum[key,i]} printf "\n"}} OFS='\t' out.txt
现在,我正在尝试替换chr1 10
行中第一行的6个值,以及chr1 11
行中第二行的6个值
我已经完成了使用以下代码更改一列中的值:
awk -F"\t" 'NR==FNR{h[$1"\t"$2]=$3;next}
{
printf $1"\t"$2"\t"$3"\t"$4"\t"h[$1"\t"$2]"\t";
for (i=6;i<=NF;i++)
{printf "%s",$i "\t"};
printf "\n"
}' OFS="\t" file1 file2
awk-F“\t”'NR==FNR{h[$1”\t“$2]=$3;next}
{
printf$1“\t“$2”\t“$3”\t“$4”\t“h[$1”\t“$2]”\t”;
对于(i=6;i这里您使用了一个内存高效的perl on liner,它应该可以解决您的问题。您可能需要添加正确的输入字段分隔符,例如-F'\t'
和一个正则表达式来跳过注释行
perl -lane 'if(!$prev || $prev eq "$F[0]:$F[1]"){push @r,[@F[4..$#F]]; push @snp,join"\t",@F[0..3]}else{for $r (@r){$o[$_]+=$$r[$_] for 0..scalar(@$r)-1}; print join"\t",($_,@o) for @snp; @snp=(join"\t",@F[0..3]); @o=(); @r=([@F[4..$#F]])} $prev="$F[0]:$F[1]"; END{for $r (@r){$o[$_]+=$$r[$_] for 0..scalar(@$r)-1}; print join"\t",($_,@o) for @snp;}' < \
<(echo -e "chr1 10 A T 1 2 3\nchr1 10 A G 1 2 3\nchr1 11 A T 4 5 6\nchr2 12 G C 7 8 9")
这是一个内存高效的perl on liner,可以解决您的问题。您可能需要添加正确的输入字段分隔符,例如-F'\t'
和一个正则表达式来跳过注释行
perl -lane 'if(!$prev || $prev eq "$F[0]:$F[1]"){push @r,[@F[4..$#F]]; push @snp,join"\t",@F[0..3]}else{for $r (@r){$o[$_]+=$$r[$_] for 0..scalar(@$r)-1}; print join"\t",($_,@o) for @snp; @snp=(join"\t",@F[0..3]); @o=(); @r=([@F[4..$#F]])} $prev="$F[0]:$F[1]"; END{for $r (@r){$o[$_]+=$$r[$_] for 0..scalar(@$r)-1}; print join"\t",($_,@o) for @snp;}' < \
<(echo -e "chr1 10 A T 1 2 3\nchr1 10 A G 1 2 3\nchr1 11 A T 4 5 6\nchr2 12 G C 7 8 9")
好吧,如果你有,试试这个datamash-H-g1,2 collapse 3,4 sum 5-10@oguzismail谢谢你的回答!我试过了,它似乎只对chr1的三个值中的两个求和10@oguzismail忘了我说过的话吧,当使用一个没有头的文件时,我保留了-H。它工作得很好!有没有办法撤消折叠并用它获取所有行最终的求和值?我不太了解datamash,但您可以使用awk撤消崩溃,只需将datamash的输出传输到awk'BEGIN{FS=OFS=“\t”}{j=split($3,a,,”);split($4,b,”);for(i=1;iHi@oguzismail!你知道是否有可能对一系列列进行拆分吗?在我的实际数据中,我有大约80列要折叠,而且编写拆分($n,a,,”)和$n=a[i]非常肮脏且不优雅
80次。我尝试嵌套两个for循环:1.迭代折叠的列,2.迭代数组“a”中的值,但无法得到所需的结果。如果有,请尝试此datamash-H-g1,2 collapse 3,4 sum 5-10@oguzismail谢谢你的回答!我已经尝试过了,似乎只对三个值中的两个求和对于chr110@oguzismail忘了我说过的话吧,当使用一个没有头的文件时,我保留了-H。它工作得非常好!有没有办法撤消折叠并获得所有具有最终求和值的行?我不太了解datamash,但您可以使用awk撤消折叠,只需将datamash的输出传输到awk'BEGIN{FS=OFS=“\t”}{j=split($3,a,,”)即可;split($4,b,“,”);for(i=1;iHi再次@oguzismail!您知道是否有可能对一系列列进行拆分吗?在我的实际数据中,我有大约80列要折叠,编写split($n,a,“,”)和$n=a[i]非常肮脏且不优雅
80次。我试图嵌套两个for循环:1.对折叠的列进行迭代,2.对数组“a”中的值进行迭代,但无法得到所需的结果hanks@pyr0!我会看看。我从未编写过perl代码,我很难理解它。非常感谢您的注释!我必须替换#
在第二行的F之前?F
是一个内置数组变量,由-a
开关初始化为@F
,可通过$F[0]
,$F[1]访问
,类似于awk中的$1
,$2
。$#
是一个内置的perlvar,用于获取数组的最后一个索引,例如$#F
了解更多信息,请参见@pyr0!我会看看。我从未编写过perl代码,很难理解它。非常感谢您的评论!我必须替换#
在第二行的F之前?F
是一个内置数组变量,由-a
开关初始化为@F
,可通过$F[0]
,$F[1]访问
,类似于awk中的$1
,$2
。$#
是一个内置的perlvar,用于获取数组的最后一个索引,例如$#F
,有关详细信息,请参阅
perl -lane 'if(!$prev || $prev eq "$F[0]:$F[1]"){push @r,[@F[4..$#F]]; push @snp,join"\t",@F[0..3]}else{for $r (@r){$o[$_]+=$$r[$_] for 0..scalar(@$r)-1}; print join"\t",($_,@o) for @snp; @snp=(join"\t",@F[0..3]); @o=(); @r=([@F[4..$#F]])} $prev="$F[0]:$F[1]"; END{for $r (@r){$o[$_]+=$$r[$_] for 0..scalar(@$r)-1}; print join"\t",($_,@o) for @snp;}' < \
<(echo -e "chr1 10 A T 1 2 3\nchr1 10 A G 1 2 3\nchr1 11 A T 4 5 6\nchr2 12 G C 7 8 9")
if(!$prev || $prev eq "$F[0]:$F[1]"){ # CHROM:POS compare to previous line
push @r,[@F[4..$#F]]; # store values in array of array reference
push @snp,join"\t",@F[0..3] # store CHROM,POS,REF,ALT
}else{
for $r (@r){ # CHROM:POS is new
$o[$_]+=$$r[$_] for 0..scalar(@$r)-1 # sum up values in array references
};
print join"\t",($_,@o) for @snp; # join CHROM,POS,REF,ALT with summed values
@snp=(join"\t",@F[0..3]); # re-initialize
@o=();
@r=([@F[4..$#F]])
}
$prev="$F[0]:$F[1]"; # store CHROM:POS info
END{ # print final lines
for $r (@r){
$o[$_]+=$$r[$_] for 0..scalar(@$r)-1
};
print join"\t",($_,@o) for @snp;
}