Wie werden zwei Dateien basierend auf der Übereinstimmung von zwei Spalten zusammengeführt?

33

Ich habe file1 mag:

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

Und eine Datei2:

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

Und möchte eine Datei3 so, dass:

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

Dies bedeutet, dass die 4. Spalte von Datei2 mit dem Namen der 2. Spalte in Datei1 gesetzt wird.

Dadong Zhang
quelle
1
Datei2 hat nur drei Spalten?
Bernhard

Antworten:

48

Dies sollte es tun:

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

Wichtig : Dies setzt voraus, dass Ihre Dateien (wie in Ihrem Beispiel) nach dem SNP-Namen sortiert sind. Wenn dies nicht der Fall ist, sortieren Sie sie zuerst:

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

Ausgabe:

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

Erklärung (von info join):

`join 'schreibt für jedes Paar von Eingabezeilen, die identische Verknüpfungsfelder haben, eine Zeile in die Standardausgabe.

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

Der obige Befehl verknüpft also die Dateien im zweiten Feld und druckt das erste, zweite und dritte Feld der ersten Datei, gefolgt vom dritten Feld der zweiten Datei.

terdon
quelle
16

Sie könnten verwenden awk:

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

Ausgabe:

$ 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

Erläuterung:

Gehen Sie durch file2( NR==FNRgilt nur für das erste Dateiargument). Speicher Spalte 3 in Hash-Array mit Spalte 2 als Schlüssel: h[$2] = $3. Gehen Sie dann file1alle drei Spalten durch und geben Sie sie aus $1,$2,$3, indem Sie die entsprechende gespeicherte Spalte aus dem Hash-Array anhängen h[$2].

Grebneke
quelle
Vielen Dank. Ich frage mich nur, was bedeutet das 'h [$ 2] = $ 3'? Tatsächlich muss ich in meinen komplexen Fällen genau die Datei1 $ 2 == Datei2 $ 2 zuordnen (die nicht in derselben Reihenfolge erforderlich sind).
Dadong Zhang
1
h[$2] = $3ist eine Hash-Zuweisung. Es wird $3als Wert und $2als Schlüssel gespeichert. Beispiel: h["name"] = "Dadong". Nun print h["name"]Ausgänge Dadong. Es macht, was Sie wollen, es stimmt genau mit der zweiten Spalte aus beiden Dateien überein.
Grebneke
6

Wenn Sie keine Bestellung benötigen, ist dies eine einfache Lösung

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

Dies setzt voraus, dass alle Zeilen drei Einträge haben und die Spalten 1 und 2 beider Dateien identisch sind (wie in Ihren Beispieldaten).

Bernhard
quelle
1
+1 für die großartige Verwendung vonpaste
Grebneke
1
@grebneke und Bernhard, da Sie Fans von zu sein scheinen, pastekönnen Sie einen Weg finden, dies mit coreutils zu beantworten ?
Terdon
@terdon - ein bescheidener Versuch: unix.stackexchange.com/a/113909/32165
grebneke
1
@terdon Ich würde dem raten, das Programm, das diesen s *** ausgibt, zu überdenken
Bernhard
An dem Format ist nichts auszusetzen, die Dateien sind durch Tabulatoren getrennt. In jedem Fall haben Sie bei dieser Art von Daten normalerweise keine Wahl, was das Format betrifft. Sie stammen aus einem anderen Programm.
Terdon