使用AWK执行类似VLOOKUP的命令

时间:2015-02-19 08:06:49

标签: awk vlookup

我有一组带有基因型数据的文件,每个文件分为3列数据,包括:MARKER,ID,GENOTYPE。

我想使用AWK(不更改文件的顺序/排序)来执行类似VLOOKUP的命令,以便将文件中的数据连接到单个文件中,如下所示:

File1中:

BIEC2-99962 HOR_233 G_G
BIEC2-9997 HOR_233 A_G
BIEC2-999748 HOR_233 C_C
BIEC2-999848 HOR_233 G_G
BIEC2-99989 HOR_233 A_A

File2:

BIEC2-9997 HOR_250 A_A
BIEC2-999748 HOR_250 C_C
BIEC2-99989 HOR_250 A_C

文件3:

BIEC2-9997 HOR_615 A_G
BIEC2-999748 HOR_615 A_C
BIEC2-999848 HOR_615 A_G
BIEC2-99989 HOR_615 A_C

预期结果:

BIEC2-99962 G_G NA NA   
BIEC2-9997 A_G A_A A_G
BIEC2-999748 C_C C_C A_C
BIEC2-999848 G_G NA A_G
BIEC2-99989 A_A A_C A_C

我将不胜感激。

谢谢!

3 个答案:

答案 0 :(得分:1)

当在最后一个文件之前甚至不知道标记的存在时插入那些NA并不是完全无关紧要的。没有它,这将是一个单行。

#!/bin/awk

func add_na() {
  for (i in a)
    if (gsub(/ /, " ", a[i]) < files)
      a[i] = a[i] " NA"
}

FNR==1 { add_na(); ++files }

{ a[$1] = a[$1] " " $3 }

END { add_na(); for (i in a) print i a[i] }

add_na函数查找未在最新文件中显示的标记(即到目前为止输出记录中的空格太少)并向其添加“NA”。
FNR规则会跟踪我们通过的文件数量,并对NA进行排序 END规则在打印结果之前添加最后一轮的NA。

答案 1 :(得分:0)

好的,确定不是awk:当涉及复杂类型时,我觉得Perl更舒服......

#!/usr/bin/perl

use strict;
my %out;
my $argc = scalar @ARGV;   # @ARGV --> command line arguments
for my $i (1..$argc){      # for all files except the first
  open(F,$ARGV[$i]);
  while(<F>){
    if(/(.*) .* (.*)/){$out{$1}[$i]=$2}
  }
}

open(F,$ARGV[0]);          # process the first
while(<F>){
  if(/(.*) .* (.*)/){
    $a=join(" ",map{ $out{$1}[$_] || "NA"} (1..$argc-1));
    print "$1 $2 $a\n"}
}

用法:

perl merge-vlookup file1 file2 file3 ... >  output 

答案 2 :(得分:0)

您可以修改输入集的此脚本:

​#!/usr/bin/env python

input_one = '''
BIEC2-99962 HOR_233 G_G
BIEC2-9997 HOR_233 A_G
BIEC2-999748 HOR_233 C_C
BIEC2-999848 HOR_233 G_G
BIEC2-99989 HOR_233 A_A
'''.strip().split()

input_two = '''
BIEC2-9997 HOR_250 A_A
BIEC2-999748 HOR_250 C_C
BIEC2-99989 HOR_250 A_C
'''.strip().split()

input_three = '''
BIEC2-9997 HOR_615 A_G
BIEC2-999748 HOR_615 A_C
BIEC2-999848 HOR_615 A_G
BIEC2-99989 HOR_615 A_C
'''.strip().split()

one_list = input_one[::3]
one_dict = dict(zip(one_list, input_one[2::3]))
two_dict = dict(zip(input_two[::3], input_two[2::3]))
three_dict = dict(zip(input_three[::3], input_three[2::3]))

print '\n'.join([' '.join([k, one_dict[k], two_dict.get(k, 'NA'), three_dict.get(k, 'NA')]) for k in one_list])

输出如下:

$ ./join_test.py
BIEC2-99962 G_G NA NA
BIEC2-9997 A_G A_A A_G
BIEC2-999748 C_C C_C A_C
BIEC2-999848 G_G NA A_G
BIEC2-99989 A_A A_C A_C

这似乎符合您的预期输出。

如果您想了解脚本的工作原理,请在列表理解之前为每个变量使用一些print语句,然后将列表理解分解为更小的部分。

最终,您可以将列表input_oneinput_twoinput_three替换为使用open()readlines()方法读取输入文件的结果。< / p>

请记住strip()split(),以便列表中的每个元素与其他元素分开,无论分隔符是空格还是换行符 - 使用print来调查其中一个元素样本输入列表,如果此要求不清楚。

我认为awk并不是这项工作的理想工具,我使用它很多。