2016-08-26 1 views
3

Ich möchte 2 Dateien zusammenführen und sie einer neuen Datei zuweisen, während eine neue nicht vorhandene Spalte hinzugefügt wird, vorzugsweise mit awk in Unix :awk, um zwei Dateien zusammenzufassen, während die Spalteneingabe geändert wird und eine zusätzliche Spalte zur Ausgabedatei hinzugefügt wird

Datei 1: VDR.txt, keinen Kopf hat, ist Raum getrennt und sieht wie folgt aus:

chr12-45000000-50000000 --- rs192072617 48225416 0.000 0.270 0.999 0 -1 -1 -1 
chr12-45000000-50000000 --- rs181728325 48225429 0.000 0.144 1.000 0 -1 -1 -1 
chr12-45000000-50000000 --- rs187216594 48225500 0.000 0.007 1.000 0 -1 -1 -1 

File 2: METAL1.tbl hat einen Header, wird wie folgt Tab getrennt und sieht :

MarkerName  Allele1 Allele2 Weight Zscore P-value Direction  HetISq HetChiSq  HetDf HetPVal 
rs192072617  a  g  2887.00 1.579 0.1143 ++  0.0  0.032 1  0.8579 
rs7929618  c  g  2887.00 -1.416 0.1568 -+  47.4 1.899 1  0.1681 
rs181728325  t  c  2887.00 1.469 0.1419 ++  73.9 3.830 1  0.05033 
rs7190157  a  c  2887.00 1.952 0.05088 +-  72.7 3.669 1  0.05542 
rs12364336  a  g  2887.00 -1.503 0.1328 -+  69.8 3.306 1  0.06902 
rs187216594  t  c  2887.00 -0.082 0.9349 +-  74.8 3.964 1  0.04649 
rs12562373  a  g  2887.00 -0.290 0.7717 -+  0.0  0.150 1  0.6984 

Dateien haben ungleiche Zeilenanzahl, die erste Datei (VDR.txt) ist viel kürzer als die zweite Datei (METAL1.tbl).

Ich möchte:

  1. Merge diese Dateien durch die dritte Spalte der ersten Datei (VDR.txt) und der ersten Spalte der zweiten Datei (METAL1.tbl).
  2. Behalten Sie nur die Spalten 1, 2, 3 und 4 aus der ersten Datei (VDR.txt) und alle Spalten aus der zweiten Datei (METAL1.tbl).
  3. Behalten Sie nur die Zeichen vor dem ersten Strich "-" aus der ersten Spalte der ersten Datei (VDR.txt)
  4. eine neue Spalte in die Ausgabedatei hinzufügen, die eine bestimmte Zeichenfolge (zB „VDR“)
  5. wiederholt
  6. Ausgabedatei muss keine Kopfzeile haben, aber wenn es notwendig ist, wäre es schön, sie wie unten angegeben zu haben.

So würde Ich mag eine Ausgabedatei haben (output.txt), die am Ende wie folgt aussieht:

gene MarkerName chr BP impute Allele1 Allele2 Weight Zscore P-value Direction HetISq HetChiSq HetDf HetPVal 
VDR rs192072617 chr12 48225416 --- a g 2887 1.579 0.1143 ++ 0 0.032 1 0.8579 
VDR rs181728325 chr12 48225429 --- t c 2887 1.469 0.1419 ++ 73.9 3.83 1 0.05033 
VDR rs187216594 chr12 48225500 --- t c 2887 -0.082 0.9349 +- 74.8 3.964 1 0.04649 

Mein Versuch, dies:

$ awk 'FNR==NR {a[$1]=$1" "$2" "$3" "$4" "$5;next}{print $3, gensub(/-.*/, "", $1), $4, $2, a[$3]}' METAL1.tbl VDR.txt 

Es geht Die Spalte chr und die Spalte ordnen den richtigen Weg, aber leider nur die gewünschten Spalten aus VDR.txt und nicht die zusammengeführte Datei.

Ich bin mir bewusst, dass dies ein ziemlich komplexes Beispiel ist, jede Hilfe oder Anregung würde sehr geschätzt werden.

Danke,
Mel

+2

So hast du einen Versuch, dieses Problem zu lösen? Wenn ja, sollten Sie dies teilen. Fragen in Form von "Hier sind meine Angaben, bitte Code für mich" werden im Allgemeinen nicht gut angenommen, aber Fragen in Form von "Hier ist mein Code, und das ist der Teil, mit dem ich Probleme habe". – Carpetsmoker

+0

Wie werden Felder in den Dateien identifiziert? Feste Breite? oder was sind die Trennzeichen? –

+0

Ich würde empfehlen, Ihre Datenprobe auf 4 Spalten oder so zu reduzieren (gerade genug, um das zugrunde liegende Problem zu lösen). Kennen Sie den Unix/Linux-Befehl 'Join'? Wenn Sie mit begrenzten Daten (wie '|' oder Tab) arbeiten können, können Sie wahrscheinlich tun, was Sie wollen in 1 Zeile. Aber ich habe mir Ihre Ein- und Ausgänge nicht genau angesehen (weil sie zu breit sind ;-), damit ich falsch liegen könnte. Viel Glück. – shellter

Antwort

2
$ cat > test.awk 
NR==FNR { 
    sub(/-.*/,"",$1)          # remove from 1st dash forward 
    a[$3]="VDR" OFS $3 OFS $1 OFS $4 OFS $2    # cols 1-4 of the 1st file 
    next           
} 
FNR==1 { 
    printf "%s", "H0" OFS "H3" OFS "H1" OFS "H4" OFS "H2" # 1st part of header 
} 
FNR==1 || $1 in a {          # header and matching rows 
    print a[$1], $0          # print'em 
} 
$ awk -f test.awk VDR.txt METAL1.tbl 
H0  H3  H1  H4  H2  MarkerName  Allele1 Allele2 Weight Zscore P-value Direction  HetISq HetChiSq  HetDf HetPVal 
VDR  rs192072617  chr12 48225416  ---  rs192072617  a  g2887.00 1.579 0.1143 ++  0.0  0.032 1  0.8579 
VDR  rs181728325  chr12 48225429  ---  rs181728325  t  c2887.00 1.469 0.1419 ++  73.9 3.830 1  0.05033 
VDR  rs187216594  chr12 48225500  ---  rs187216594  t  c2887.00 -0.082 0.9349 +-  74.8 3.964 1  0.04649 

Als Einzeiler:

awk 'NR==FNR { sub(/-.*/,"",$1); a[$3]="VDR" OFS $3 OFS $1 OFS $4 OFS $2; next} FNR==1 {printf "%s", "H0" OFS "H3" OFS "H1" OFS "H4" OFS "H2"} FNR==1 || $1 in a {print a[$1], $0}' VDR.txt METAL1.tbl 
+0

Vielen Dank für die Hilfe, das funktioniert gut, aber ich war auf der Suche nach einem One-Liner wie die Lösung von Jonathan Leffler. –

1

ich die beiden Datendateien sortiert haben den join Befehl verwenden - dies wirkt sich auf die Reihenfolge der Zeilen in der Ausgabe - wenn das nicht erwünscht ist, ich

export LANG=C 
genef=$1 
metalf=$2 
gene=$(basename $genef .txt) 
join -13 -21 <(sort -k3,3 $genef) <(sort -k1,1 $metalf)| 
awk -vgene=$gene ' 
{ 
    marker=$1 
    chr=substr($2, 1, index($2, "-")-1) 
    bp=$4 
    impute=$3 
    printf("%s\t%s\t%s\t%s\t%s", gene, marker, chr, bp, impute) 
    for(i=12; i<=NF; ++i) 
    printf("\t%s", $i) 
    printf("\n") 
} 
' 
einen anderen Ansatz verwenden können

dies ist die Tab-separierte Ausgabe

VDR  rs181728325  chr12 48225429  ---  t  c  2887.00 1.469 0.1419 ++  73.9 3.830 1  0.05033 
VDR  rs187216594  chr12 48225500  ---  t  c  2887.00 -0.082 0.9349 +-  74.8 3.964 1  0.04649 
VDR  rs192072617  chr12 48225416  ---  a  g  2887.00 1.579 0.1143 ++  0.0  0.032 1  0.8579 
+0

Danke für den Vorschlag, aber der Grund, warum ich nicht "Join" wollte, war, dass ich die Dateien bestellen musste ... Dies wäre eine einfache Aufgabe für die erste Datei (VDR.txt), aber nicht für die zweite (METAL1 .tbl) was eine ziemlich große (~ 600 Mb) Datei ist. Das Sortieren von METAL1.tbl hat mir immer wieder Fehler gemacht und mir mehr Verarbeitungszeit eingebracht, deshalb suchte ich nach einer Lösung um awk. –

+0

guter Punkt - eine Art von 600MB ist ziemlich schnell - aber ein einziger Durchlauf mit awk ist immer gut - welche Fehler sehen Sie mit der Sorte? – pakistanprogrammerclub

3

Solange die Titelzeile nicht benötigt wird, es i s geradlinig in einem einzigen, ziemlich einfach awk Skript:

$ awk 'FNR == NR { sub(/-.*/, "", $1); row[$3] = "VDR " $3 " " $1 " " $4 " " $2 } 
>  FNR != NR { if ($1 in row) { name = $1; $1 = ""; print row[name] $0 } }' \ 
>  VDR.txt METAL1.tbl 
VDR rs192072617 chr12 48225416 --- a g 2887.00 1.579 0.1143 ++ 0.0 0.032 1 0.8579 
VDR rs181728325 chr12 48225429 --- t c 2887.00 1.469 0.1419 ++ 73.9 3.830 1 0.05033 
VDR rs187216594 chr12 48225500 --- t c 2887.00 -0.082 0.9349 +- 74.8 3.964 1 0.04649 
$ 

Die Dateien in der Reihenfolge aufgeführt werden muss, damit sie angezeigt arbeiten.

Die Zeile FNR == NR verarbeitet die erste Datei.Die sub beseitigt den ersten Strich und alles danach im ersten Feld; Die Zuweisung wird durch den Markenname in $3 verschlüsselt und enthält die Informationen für den Anfang der Zeile - den festen Code, den Markernamen, die reduzierte Chromosomennummer, den BP und den Satz von Bindestrichen mit der Bezeichnung "Impute".

Die FNR != NR Zeile verarbeitet die anderen Datei (en). Wenn der Wert in Spalte 1 mit einem Schlüssel im Array row übereinstimmt, entfernen Sie den Schlüssel aus der aktuellen Zeile (der in-situ eine Leerstelle am Anfang von $0 hinterlässt) und drucken Sie dann den Wert row, verkettet mit $0.

Es gibt keine Notwendigkeit, die Überschriftenlinie besonders zu behandeln; Der Wert MarkerName stimmt mit keinem der tatsächlichen Markernamen aus der ersten Datei überein, sodass die Zeile einfach ignoriert wird.

+0

und fügen Sie 'BEGIN {print" Header Sie wollen "}' –

Verwandte Themen