Removendo linhas que contêm NA em todas as colunas


8

Eu tenho um arquivo delimitado por tabulação que se parece com isso:

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

O número de campos em cada linha é fixo e é o mesmo. Quero remover essas linhas do arquivo acima, onde todos os campos de cada linha da coluna 2 à última são NA. Em seguida, a saída deve se parecer com:

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

Se os campos que não são NA sempre são números inteiros não negativos, uma expressão regular tão simples como \s\ddiferencia entre as linhas "boa" e "ruim".
Roman Odaisky

se você está fazendo bioinformática trabalho por que não usar R
QWR

Porque eu estou usando ferramentas de linha de comando upstream para gerar esse arquivo e eu preferirei a solução awk ou perl se não precisar salvar o arquivo para abrir no R. É claro que no R você pode remover isso com uma is.na verificação, se eu pensar
user3138373

Respostas:


16

Com awk:

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

Faça um loop pelos campos começando no segundo campo e imprima a linha se um campo que não contiver NAfor encontrado. Então quebre o ciclo.


10

Usando o GNU sed

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

Breve explicação:

g[0-9]\+\(\s*NA\s*\)\+$é uma correspondência de regex gseguida por pelo menos um dígito e, em seguida, qualquer número de NAs com espaços opcionais até o final da linha.

sed -e '/<regex>/d' exclui todas as linhas que correspondem <regex>

Uma regexp mais padrão com o mesmo significado seria:

sed -Ee '/g[0-9]+([[:space:]]*NA[[:space:]]*)+$/d' filename

4
Observe que \+e \ssão expressões regulares não-padrão e corresponderá a um simples +ou sna maioria das sedversões. Use em \{1,\}vez de \+e em [[:space:]]vez de \ster código portátil.
Philippos

9

Com a allpartir do módulo 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

9

Com grep:

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

Isso faz com que o grep não exiba ( -v) linhas onde a linha inteira ( -x) corresponde:

  • minúsculas g na primeira coluna, seguidas por um ou mais dígitos
  • qualquer número de instâncias de espaço em branco seguido por NA
  • espaço em branco à direita opcional

11
+1, mas nota também que o número de campos é fixo, então você poderia usar {4}em vez de *depois do NAgrupo, e você pode querer mudar o primeiro [[:blank:]]*a [[:blank:]]+fazer os separadores de espaço em branco obrigatório. Independentemente disso, nunca entendi por que todo mundo insiste em retirar a awkbazuca para resolver esses problemas simples de filtragem que greplidam com facilidade.
Kevin

Obrigado pelo feedback, @Kevin. Eu incorporei sua primeira sugestão, mas mantenho a outra *para que esta solução funcione igualmente bem para qualquer número arbitrário de NAcolunas, desde que todas sejam NA.
Jim L.

2

Você poderia tentar:

$ 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 
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.