Comment fusionner deux fichiers en fonction de la correspondance de deux colonnes?

33

J'ai file1 aime:

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

Et un fichier2:

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

Et voudrait un fichier3 tel 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

Ce qui signifie mettre la 4ème colonne de fichier2 en fichier1 par le nom de la 2ème colonne.

Dadong Zhang
la source
1
File2 n'a que trois colonnes?
Bernhard

Réponses:

48

Cela devrait le faire:

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

Important : cela suppose que vos fichiers sont triés (comme dans votre exemple) selon le nom SNP. Si ce n'est pas le cas, triez-les d'abord:

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

Sortie:

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

Explication (de info join):

`join 'écrit sur la sortie standard une ligne pour chaque paire de lignes d'entrée qui ont des champs de jointure identiques.

`-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.

Ainsi, la commande ci-dessus joint les fichiers du deuxième champ et imprime les 1er, 2e et 3e champs du fichier un, suivis du 3e champ du fichier2.

terdon
la source
16

Vous pouvez utiliser awk:

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

sortie:

$ 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

Explication:

Parcourez file2( NR==FNRn'est vrai que pour le premier argument de fichier). Enregistrer la colonne 3 dans le hachage tableau en utilisant la colonne 2 comme la clé: h[$2] = $3. Parcourez ensuite file1et affichez les trois colonnes $1,$2,$3, en ajoutant la colonne enregistrée correspondante à partir du tableau de hachage h[$2].

grebneke
la source
Merci beaucoup. Je me demande simplement ce que signifie le «h [$ 2] = $ 3»? En fait, je dois faire correspondre exactement le fichier1 $ 2 == fichier2 $ 2 dans mes cas complexes (qui ne sont pas nécessaires dans le même ordre).
Dadong Zhang
1
h[$2] = $3est une affectation de hachage. Il enregistre $3comme valeur et $2comme clé. Exemple: h["name"] = "Dadong". Maintenant, les print h["name"]sorties Dadong. Il fait ce que vous voulez, il correspond exactement à la deuxième colonne des deux fichiers.
grebneke
6

Si vous n'avez besoin d'aucune commande, une solution simple serait

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

Cela suppose que toutes les lignes ont trois entrées et que les colonnes 1 et 2 des deux fichiers sont identiques (comme dans vos données d'exemple)

Bernhard
la source
1
+1 pour une bonne utilisation depaste
grebneke
1
@grebneke et Bernhard, puisque vous semblez être fans de, pastepouvez-vous trouver un moyen de répondre à cela avec coreutils?
terdon
@terdon - une humble tentative: unix.stackexchange.com/a/113909/32165
grebneke
1
@terdon Je conseillerais au de reconsidérer le programme qui produit ce s ***
Bernhard
Rien de mal avec le format, des fichiers séparés par des tabulations parfaitement décents. Dans tous les cas, avec ce type de données, vous n'avez généralement pas le choix du format, elles proviennent d'un autre programme.
terdon