Como mesclar dois arquivos com base na correspondência de duas colunas?


33

Tenho file1 gosta:

0   AFFX-SNP-000541  NA
0   AFFX-SNP-002255  NA
1   rs12103          0.6401
1   rs12103_1247494  0.696
1   rs12142199       0.7672

E um arquivo2:

0   AFFX-SNP-000541   1
0   AFFX-SNP-002255   1
1   rs12103           0.5596
1   rs12103_1247494   0.5581
1   rs12142199        0.4931

E gostaria de um arquivo3 que:

0   AFFX-SNP-000541     NA       1
0   AFFX-SNP-002255     NA       1
1   rs12103             0.6401   0.5596
1   rs12103_1247494     0.696    0.5581
1   rs12142199          0.7672   0.4931

O que significa colocar a quarta coluna do arquivo2 em arquivo1 pelo nome da 2ª coluna.


1
Arquivo2 só tem três colunas?
Bernhard

Respostas:


48

Isso deve servir:

join -j 2 -o 1.1,1.2,1.3,2.3 file1 file2

Importante : isso pressupõe que seus arquivos sejam classificados (como no seu exemplo) de acordo com o nome do SNP. Se não estiverem, classifique-os primeiro:

join -j 2 -o 1.1,1.2,1.3,2.3 <(sort -k2 file1) <(sort -k2 file2)

Saída:

0 AFFX-SNP-000541 NA 1
0 AFFX-SNP-002255 NA 1
1 rs12103 0.6401 0.5596
1 rs12103_1247494 0.696 0.5581
1 rs12142199 0.7672 0.4931

Explicação (de info join):

`join 'grava na saída padrão uma linha para cada par de linhas de entrada que possuem campos de junção idênticos.

`-1 FIELD'
     Join on field FIELD (a positive integer) of file 1.

`-2 FIELD'
     Join on field FIELD (a positive integer) of file 2.

`-j FIELD'
     Equivalent to `-1 FIELD -2 FIELD'.

`-o FIELD-LIST'

 Otherwise, construct each output line according to the format in
 FIELD-LIST.  Each element in FIELD-LIST is either the single
 character `0' or has the form M.N where the file number, M, is `1'
 or `2' and N is a positive field number.

Portanto, o comando acima une os arquivos no segundo campo e imprime o primeiro, o segundo e o terceiro campos do arquivo um, seguidos pelo terceiro campo do arquivo2.


16

Você poderia usar awk:

$ awk 'NR==FNR {h[$2] = $3; next} {print $1,$2,$3,h[$2]}' file2 file1 > file3

saída:

$ cat file3
0 AFFX-SNP-000541 NA 1
0 AFFX-SNP-002255 NA 1
1 rs12103 0.6401 0.5596
1 rs12103_1247494 0.696 0.5581
1 rs12142199 0.7672 0.4931

Explicação:

Percorrer file2( NR==FNRé verdade apenas para o primeiro argumento de arquivo). Guardar coluna 3 na mistura-matriz usando coluna 2 como chave: h[$2] = $3. Em seguida, percorra file1e produza todas as três colunas $1,$2,$3, anexando a coluna salva correspondente do hash-array h[$2].


Muito obrigado. Apenas imaginando, o que significa 'h [$ 2] = $ 3'? Na verdade, preciso corresponder exatamente ao arquivo1 $ 2 == arquivo2 $ 2 nos meus casos complexos (que não são necessários na mesma ordem).
Dadong Zhang

1
h[$2] = $3é uma atribuição de hash. Salve $3como valor e $2como chave. Exemplo: h["name"] = "Dadong". Agora, print h["name"]saídas Dadong. Ele faz o que você deseja, corresponde exatamente à segunda coluna dos dois arquivos.
grebneke

6

Se você não precisar de nenhum pedido, uma solução simples seria

paste file{1,2} | awk '{print $1,$2,$3,$6}' > file3

Isso pressupõe que todas as linhas têm três entradas e as colunas 1 e 2 dos dois arquivos são iguais (como nos dados de exemplo)


1
+1 para um ótimo uso de #paste
grebneke

1
@grebneke e Bernhard, já que você parece ser fã, pasteconsegue descobrir uma maneira de responder isso com coreutils?
terdon

@terdon - uma humilde tentativa: unix.stackexchange.com/a/113909/32165
grebneke

1
@terdon eu aconselho a reconsiderar o programa que está a emitir este s ***
Bernhard

Nada de errado com o formato, arquivos separados por guias perfeitamente decentes. De qualquer forma, com esse tipo de dados você geralmente não tem escolha quanto ao formato, ele sai de outro programa.
terdon
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.