Exclui uma linha que contenha 0 mais que 'x' quantidade de vezes

3

Eu tenho um arquivo grande separado por vírgula. Eu preciso filtrar as linhas que contêm x quantidade de colunas contendo zeros (excluindo a primeira linha). Para simplificar, digamos que eu queira filtrar linhas com mais de 4 zeros:

    gene,v1,v2,v3,v4,v5,v6,v7
    gene1,0,1,5,0,0,4,100
    gene2,1,0,0,0,5,210,2
    gene3,0,0,0,0,6,0,0

retornaria:

    gene,v1,v2,v3,v4,v5,v6,v7
    gene1,0,1,5,0,0,4,100
    gene2,1,0,0,0,5,210,2

Filtrando "gene3".

Veja o que eu tentei (tentando e não usando ', 0' como um delimitador):

awk -F',0' 'NF<4 {print}' file.csv
    
por Johnny 02.06.2018 / 01:23

6 respostas

2

abordagem do KISS, com awk

awk -F, '{c = 0; for(i=1; i<=NF; i++) {c += $i == "0" ? 1 : 0}} c <= 3' file.csv
    gene,v1,v2,v3,v4,v5,v6,v7
    gene1,0,1,5,0,0,4,100
    gene2,1,0,0,0,5,210,2

com perl

perl -F, -ne 'print unless (grep { $_ eq "0" } @F) > 3' file.csv
    gene,v1,v2,v3,v4,v5,v6,v7
    gene1,0,1,5,0,0,4,100
    gene2,1,0,0,0,5,210,2
    
por 02.06.2018 / 01:35
3

Com awk -F',0' , três cópias de ,0 serão consideradas como três separadores , dando quatro campos no total. Portanto, se você usar awk -F',0' 'NF<5 {print}' , deverá ver as linhas corretas na saída.

,0 também corresponderá a strings como 213,0123 , que você pode ou não querer separar como zero.

Assim, você também pode usar , como o separador de campo e contar os campos que têm apenas apenas um zero:

awk -F, '{z=0; for (i = 1 ; i <= NF ; i++) if ($i == 0) z++} z <= 4' file.csv
    
por 02.06.2018 / 01:37
3

Você também pode resolver seu problema usando expressões regulares e grep .

grep -Ev '(,0(,[^0,]+)*){4,}' file.csv

Eu testei este arquivo:

gene,v1,v2,v3,v4,v5,v6,v7
gene1,0,1,5,0,0,4,100
gene2,1,0,0,0,5,210,2
gene3,0,0,0,0,6,0,0
gene4,0,0,0,4,6,0,0
gene5,0,1,0,4,6,0,0

Existem algumas suposições:

  • nenhum número diferente de zero começa com zero,
  • os números zero contêm apenas um zero,
  • todos os números são inteiros.

A expressão regular pode ser estendida para abordar esses casos caso você precise.

    
por 02.06.2018 / 10:38
1

Certamente a resposta é simplesmente

awk -F,0 'NF<5' file.csv

Use um delimitador de ", 0" e onde o número de campos é menor que 5, execute a ação padrão que é imprimir.

Eu testei neste arquivo

gene,v1,v2,v3,v4,v5,v6,v7
gene1,0,1,5,0,0,4,100
gene2,1,0,0,0,5,210,2
gene3,0,0,0,0,6,0,0
gene4,0,0,0,4,6,0,0
gene5,0,1,0,4,6,0,0

Que gerou esse resultado

gene,v1,v2,v3,v4,v5,v6,v7
gene1,0,1,5,0,0,4,100
gene2,1,0,0,0,5,210,2

Experimente online!

    
por 02.06.2018 / 12:07
1

Se todos os números forem inteiros, usando GNU awk que suporta limites de palavras \<...\> , você poderia fazer

gawk 'gsub(/\<0\>/, "0") <5' infile
    
por 02.06.2018 / 07:37
0

Isso pode ser feito com o seguinte:

¶ separe os registros em uma vírgula

  perl -F'/,(?=0,|0$)/' -lane 'print if $#F < 4' csv.file 

° split on those commas to the right of whom we see either a 0, or a 0 at the end.

° the array formed by splitting up the record ($_) is (@F) and whose last index ($#) will have how many such commas were there.

¶ sed baseado

 sed -ne '
     h;1b print
     s/,/,,/g;s/$/,/;t reset
     :reset;s/,0,/&/4;t
     :print;g;p
 '  csv.file

°  we double the commas as this involves overlapping matches. Also provide a comma at the end for uniform matching. 
 ° a dummy t command is run first to clear the test flag, OTW the actual t command that follows misfires.
° a s/// command is run to do a fourth substitution. If it succeeds => there are at least four pure zero fields. We don't want this so the labelless t command shall take the conrol to end of any further processing. The -n sed option will prevent it from being printed.
° now when the substitution failed => there were three or less such pure zero fields and we want such lines.
° before making changes we had stored the original unmodified line in hold space so we get it back and print it.
    
por 03.06.2018 / 14:25