Entfernen von Zeilen mit NA in jeder Spalte

8

Ich habe eine durch Tabulatoren getrennte Datei, die folgendermaßen aussieht:

gene    v1  v2  v3  v4
g1  NA  NA  NA  NA
g2  NA  NA  2   3
g3  NA  NA  NA  NA
g4  1   2   3   2

Die Anzahl der Felder in jeder Zeile ist fest und gleich. Ich möchte diese Zeilen aus der obigen Datei entfernen, in der alle Felder für jede Zeile von Spalte 2 bis zuletzt NA sind. Dann sollte die Ausgabe folgendermaßen aussehen:

gene    v1  v2  v3  v4
g2  NA  NA  2   3
g4  1   2   3   2 
user3138373
quelle
Wenn die Nicht-NA-Felder immer nichtnegative Ganzzahlen sind, unterscheidet ein so einfacher regulärer Ausdruck \s\dzwischen den Zeilen „gut“ und „schlecht“.
Roman Odaisky
Wenn Sie Bioinformatik arbeiten, warum nicht einfach R
qwr
Da ich vorab Befehlszeilentools verwende, um diese Datei zu generieren, und ich eine awk- oder perl-Lösung bevorzuge, wenn ich die Datei nicht speichern muss, um sie in R zu öffnen. Natürlich können Sie diese in R entfernen is.na ,
indem

Antworten:

16

Mit awk:

awk '{ for (i=2;i<=NF;i++) if ($i!="NA"){ print; break } }' file

Durchlaufen Sie die Felder ab dem zweiten Feld und drucken Sie die Zeile, wenn ein Feld gefunden wird, das keine enthält NA. Dann brechen Sie die Schleife.

Freddy
quelle
10

Mit GNU sed

sed -e '/g[0-9]\+\(\s*NA\s*\)\+$/d' filename

Kurze Erklärung:

g[0-9]\+\(\s*NA\s*\)\+$ist eine Regex-Übereinstimmung, ggefolgt von mindestens einer Ziffer, dann einer beliebigen Anzahl von NAs mit optionalen Leerzeichen zwischen bis zum Ende der Zeile.

sed -e '/<regex>/d' löscht alle übereinstimmenden Zeilen <regex>

Ein Standard-Regexp mit derselben Bedeutung wäre:

sed -Ee '/g[0-9]+([[:space:]]*NA[[:space:]]*)+$/d' filename
eike
quelle
4
Bitte beachten Sie, dass \+und \snicht standardmäßige reguläre Ausdrücke sind und mit einer einfachen +oder sin den meisten sedVersionen übereinstimmen . Verwenden Sie \{1,\}anstelle von \+und [[:space:]]anstelle von \sportablem Code.
Philippos
9

Mit allaus dem Perl List :: Util-Modul:

$ perl -MList::Util=all -alne 'shift @F; print unless all { $_ eq "NA" } @F' file
gene  v1  v2  v3  v4
g2    NA  NA  2   3
g4    1   2   3   2
Steeldriver
quelle
9

Mit grep:

egrep -v -x 'g[0-9]+([[:blank:]]+NA)*[[:blank:]]*' filename

Dies führt dazu, dass grep keine ( -v) Zeilen anzeigt , in denen die gesamte Zeile ( -x) übereinstimmt:

  • Kleinbuchstabe g in der ersten Spalte, gefolgt von einer oder mehreren Ziffern
  • Beliebig viele Leerzeichen, gefolgt von NA
  • optionales nachfolgendes Leerzeichen
Jim L.
quelle
1
Auch +1, aber beachten Sie, dass die Anzahl der Felder festgelegt ist, so können Sie verwenden , {4}anstatt *nach der NAGruppe, und Sie können die erste ändern möchten [[:blank:]]*zu [[:blank:]]+machen , um die Leerzeichen Separatoren obligatorisch. Unabhängig davon habe ich nie verstanden, warum jeder darauf besteht, die awkPanzerfaust herauszuziehen , um diese einfachen Filterprobleme zu lösen, grepdie leicht zu handhaben sind.
Kevin
Vielen Dank für das Feedback, @ Kevin. Ich habe Ihren ersten Vorschlag aufgenommen, aber ich behalte den anderen bei, *damit diese Lösung für eine beliebige Anzahl von NASpalten gleich gut funktioniert , solange sie alle NA sind.
Jim L.
2

Du könntest es versuchen:

$ grep -P '\t(?!NA(\t|$))' file

$ sed -e 'h;s/\tNA//g;/\t/!d;g' file

$ perl -MList::MoreUtils=any -F'\t' -lane 'print if any { ! /^NA$/ } @F[1..$#F]' file 
Rakesh Sharma
quelle