Suppression de lignes contenant NA dans chaque colonne

8

J'ai un fichier délimité par des tabulations qui ressemble à ceci:

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

Le nombre de champs dans chaque ligne est fixe et identique. Je veux supprimer ces lignes du fichier ci-dessus où tous les champs pour chaque ligne de la colonne 2 à la dernière sont NA. Ensuite, la sortie devrait ressembler à:

gene    v1  v2  v3  v4
g2  NA  NA  2   3
g4  1   2   3   2 
user3138373
la source
Si les champs non-NA sont toujours des entiers non négatifs, une expression régulière aussi simple que \s\ddifférencie les «bonnes» et les «mauvaises» lignes.
Roman Odaisky
si vous faites un travail de bioinformatique, pourquoi ne pas simplement utiliser R
qwr
Parce que j'utilise des outils de ligne de commande en amont pour générer ce fichier et je préférerai une solution awk ou perl si je n'ai pas à enregistrer le fichier pour l'ouvrir dans R. Bien sûr, dans R, vous pouvez supprimer cela en is.na vérifiant si je pense
user3138373

Réponses:

16

Avec awk:

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

Parcourez les champs à partir du deuxième champ et imprimez la ligne si un champ ne contenant pas NAest trouvé. Brisez ensuite la boucle.

Freddy
la source
10

Utiliser GNU sed

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

Brève explication:

g[0-9]\+\(\s*NA\s*\)\+$est une correspondance d'expression régulière gsuivie d'au moins un chiffre, puis d'un nombre quelconque de NAs avec des espaces facultatifs entre les deux jusqu'à la fin de la ligne.

sed -e '/<regex>/d' supprime toutes les lignes qui correspondent <regex>

Une expression rationnelle plus standard avec la même signification serait:

sed -Ee '/g[0-9]+([[:space:]]*NA[[:space:]]*)+$/d' filename
eike
la source
4
S'il vous plaît noter que \+et \ssont des expressions régulières non standard et correspondent simple +ou sdans la plupart des sedversions. Utilisez \{1,\}au lieu de \+et [[:space:]]au lieu d' \savoir un code portable.
Philippos
9

Avec alldu module Perl List :: Util:

$ 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
tournevis
la source
9

Avec grep:

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

Ceci fait que grep n'affiche pas les -vlignes ( ) où la ligne entière ( -x) correspond:

  • minuscule g dans la première colonne, suivi d'un ou plusieurs chiffres
  • un nombre quelconque d'instances d'espaces suivis de NA
  • espace de fin facultatif
Jim L.
la source
1
+1, mais notez aussi que le nombre de champs est fixe, vous pouvez donc utiliser au {4}lieu de *après le NAgroupe, et vous voudrez peut - être changer le premier [[:blank:]]*à [[:blank:]]+faire les séparateurs d'espaces blancs obligatoires. Quoi qu'il en soit, je n'ai jamais compris pourquoi tout le monde insiste pour retirer le awkbazooka pour résoudre ces simples problèmes de filtrage qui se grepgèrent facilement.
Kevin
Merci pour vos commentaires, @Kevin. J'ai incorporé votre première suggestion, mais je retiens l'autre *afin que cette solution fonctionne aussi bien pour n'importe quel nombre arbitraire de NAcolonnes, tant qu'elles sont toutes NA.
Jim L.
2

Tu pourrais essayer:

$ 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
la source