Contar o número de uma repetição de substring em uma string

6

Eu tenho um arquivo que contém uma sequência genética como:

ATGTGGATGGTGGGTTACAATGAAGGTGGTGAGTTCAACATGGCTGATTATCCATTCAGTGGAAGGAAACTAAGGCCTCTCATTCCAAGACCAGTCCCAGTCCCTACTACTTCTCCTAACAGCACTTCAACTATAACTCCTTCCTTAAACCGCATTCATGGTGGCAATGATTTATTTTCACAATATCATCACAATCTGCAGCAGCAAGCATCAGTAGGAGATCATAGCAAGAGATCAGAGTTGAATAATAATAATAATCCATCTGCAGCAGTTGTGGTGAGTTCAAGATGGAATCCAACACCAGAACAGTTAAGAGCACTGGAAGAATTGTATAGAAGAGGAACAAGAACACCTTCTGCTGAGCAAATCCAACAAATAACTGCCCAGCTTAGAAAATTTGGAAAAATTGAAGGCAAAAATGTTTTCTATTGGTTTCAGAATCACAAAGCCAGAGAAAGGCAAAAACGACGGCGTCAAATGGAATCAGCAGCTGCTGAGTTTGATTCTGCTATTGAAAAGAAAGACTTAGGCGCAAGTAGG


ACAGTGTTTGAAGTTGAACACACTAAAAACTGGCTACCATCTACAAATTCCAGTACCAGTACTCTTCATCTTGCAGAGGAATCTGTTTCAATTCAAAGGTCAGCAGCAGCAAAAGCAGATGGATGGCTCCAATTCGATGAAGCAGAATTACAGCAAAGAAGAAACTTTATGGAAAGGAATGCCACGTGGCATATGATGCAGTTAACTTCTTCTTGTCCTACAGCTAGCATGTCCACCACAACCACAGTAACAACTAGACTTATGGACCCAAAACTCATCAAGACCCATGAACTCAACTTATTCATTTCACCTCACACATACAAAGAAAGAGAAAACGCTTTTATCCACTTAAATACTAGTAGTACTCATCAAAATGAATCTGATCAAACCCTTCAACTTTTCCCAATAAGGAATGGAGATCATGGATGCACTGATCATCATCATCATCATCATAACATTATCAAAGAGACACAGATATCAGCTTCAGCAATCAATGCACCCAACCAGTTTATTGAGTTTCTTCCCTTGAAAAACTGA

Estou tentando contar o número de ocorrências de substring "ATG" na string acima (que é apenas uma linha sem quebras de linha.) Meu arquivo contém dezenas (10s) dessas sequências e quero poder contar quantos "ATG" em cada sequência. Cada sequência é separada das outras por uma linha vazia.

Eu tentei o grep, mas não sabia quais opções eu deveria usar (se o grep conseguisse resolver o problema) e eu procurava por qualquer exemplo de awk, mas não encontrei nenhum.

    
por Faiz Lotfy 22.09.2015 / 05:55

4 respostas

7

Retorna o número de ocorrências de ATG em cada linha:

awk -F'ATG' 'NF{print NF-1}' testfile

Isso funciona para arquivos com uma ou várias linhas.

Exemplo 1

Considere este arquivo de teste:

$ cat testfile
xxATGxxATG

ATGxxxATGxxx

xxATGxxxxATGxxATGxx

O código conta corretamente as ocorrências de ATG:

$ awk -F'ATG' 'NF{print NF-1}' testfile
2
2
3

Exemplo 2

Usando o exemplo na versão atual da pergunta:

$ cat >file1
ATGTGGATGGTGGGTTACAATGAAGGTGGTGAGTTCAACATGGCTGATTATCCATTCAGTGGAAGGAAACTAAGGCCTCTCATTCCAAGACCAGTCCCAGTCCCTACTACTTCTCCTAACAGCACTTCAACTATAACTCCTTCCTTAAACCGCATTCATGGTGGCAATGATTTATTTTCACAATATCATCACAATCTGCAGCAGCAAGCATCAGTAGGAGATCATAGCAAGAGATCAGAGTTGAATAATAATAATAATCCATCTGCAGCAGTTGTGGTGAGTTCAAGATGGAATCCAACACCAGAACAGTTAAGAGCACTGGAAGAATTGTATAGAAGAGGAACAAGAACACCTTCTGCTGAGCAAATCCAACAAATAACTGCCCAGCTTAGAAAATTTGGAAAAATTGAAGGCAAAAATGTTTTCTATTGGTTTCAGAATCACAAAGCCAGAGAAAGGCAAAAACGACGGCGTCAAATGGAATCAGCAGCTGCTGAGTTTGATTCTGCTATTGAAAAGAAAGACTTAGGCGCAAGTAGG


ACAGTGTTTGAAGTTGAACACACTAAAAACTGGCTACCATCTACAAATTCCAGTACCAGTACTCTTCATCTTGCAGAGGAATCTGTTTCAATTCAAAGGTCAGCAGCAGCAAAAGCAGATGGATGGCTCCAATTCGATGAAGCAGAATTACAGCAAAGAAGAAACTTTATGGAAAGGAATGCCACGTGGCATATGATGCAGTTAACTTCTTCTTGTCCTACAGCTAGCATGTCCACCACAACCACAGTAACAACTAGACTTATGGACCCAAAACTCATCAAGACCCATGAACTCAACTTATTCATTTCACCTCACACATACAAAGAAAGAGAAAACGCTTTTATCCACTTAAATACTAGTAGTACTCATCAAAATGAATCTGATCAAACCCTTCAACTTTTCCCAATAAGGAATGGAGATCATGGATGCACTGATCATCATCATCATCATCATAACATTATCAAAGAGACACAGATATCAGCTTCAGCAATCAATGCACCCAACCAGTTTATTGAGTTTCTTCCCTTGAAAAACTGA

Isso resulta em:

$ awk -F'ATG' 'NF{print NF-1}' file1
9
15

Como funciona

o awk implicitamente percorre todas as linhas de um arquivo. Cada linha é dividida em campos.

  • -F'ATG'

    Isso diz ao awk para usar ATG como o separador de campo.

  • NF{print NF-1}

    Para cada linha não vazia, isso indica ao awk para imprimir o número de campos menos 1.

    (Nas linhas vazias, o número de campos, NF , é zero. Portanto, a condição NF é avaliada como falsa nessas linhas, efetivamente pulando sobre elas.)

por 22.09.2015 / 06:05
3

De man grep

-o, --only-matching
    Print only the matched (non-empty) parts of a matching line, with each such part on a separate output line.

Então você pode tentar

$ grep -o 'ATG' file | wc -l
    
por 22.09.2015 / 06:03
3

Melhorando a idéia do tachomi grep -o, com o testfile de John1024, aqui está uma maneira de incluir tanto a contagem quanto indicar qual linha do arquivo de entrada tem essa contagem, caso você esteja gerando milhares de linhas, e em um Posteriormente, pode ser necessário refazer exatamente de que linha veio uma contagem.

Primeiro, um arquivo de amostra, baseado em uma versão ligeiramente diferente do testfile de John1024,

$ cat testfile2
xxATGxxATG

ATGxxxATGxxx

xxATGxxxxATGxxATG

Se você adicionar -n para mostrar o número da linha na entrada original, você verá:

$ grep -no ATG testfile2
1:ATG
1:ATG
3:ATG
3:ATG
5:ATG
5:ATG
5:ATG

Finalmente, use uniq -c para fazer a contagem:

$ grep -no ATG testfile2 | uniq -c
  2 1:ATG
  2 3:ATG
  3 5:ATG

Agora, você tem as duas contagens de ATG , bem como o número da linha (do arquivo de entrada) de onde veio a contagem.

Você também pode convertê-lo para mostrar apenas contagens, fazendo uso de awk :

$ grep -no ATG testfile2 | uniq -c | awk '{print $1}'
2
2
3

O $1 do awk refere-se ao primeiro campo.

    
por 22.09.2015 / 07:03
1

Você pode usar a seção nl elimiter do -d para redefinir as contagens por conjunto.

Depois de copiar seus dados para minha área de transferência ...

xsel |
sed '/./!G;s/\n/::::::&::::/;s/ATG/&\
/g' | nl -d:: -v0

... rende ...

 0  ATG
 1  TGGATG
 2  GTGGGTTACAATG
 3  AAGGTGGTGAGTTCAACATG
 4  GCTGATTATCCATTCAGTGGAAGGAAACTAAGGCCTCTCATTCCAAGACCAGTCCCAGTCCCTACTACTTCTCCTAACAGCACTTCAACTATAACTCCTTCCTTAAACCGCATTCATG
 5  GTGGCAATG
 6  ATTTATTTTCACAATATCATCACAATCTGCAGCAGCAAGCATCAGTAGGAGATCATAGCAAGAGATCAGAGTTGAATAATAATAATAATCCATCTGCAGCAGTTGTGGTGAGTTCAAGATG
 7  GAATCCAACACCAGAACAGTTAAGAGCACTGGAAGAATTGTATAGAAGAGGAACAAGAACACCTTCTGCTGAGCAAATCCAACAAATAACTGCCCAGCTTAGAAAATTTGGAAAAATTGAAGGCAAAAATG
 8  TTTTCTATTGGTTTCAGAATCACAAAGCCAGAGAAAGGCAAAAACGACGGCGTCAAATG
 9  GAATCAGCAGCTGCTGAGTTTGATTCTGCTATTGAAAAGAAAGACTTAGGCGCAAGTAGG


 0  ACAGTGTTTGAAGTTGAACACACTAAAAACTGGCTACCATCTACAAATTCCAGTACCAGTACTCTTCATCTTGCAGAGGAATCTGTTTCAATTCAAAGGTCAGCAGCAGCAAAAGCAGATG
 1  GATG
 2  GCTCCAATTCGATG
 3  AAGCAGAATTACAGCAAAGAAGAAACTTTATG
 4  GAAAGGAATG
 5  CCACGTGGCATATG
 6  ATG
 7  CAGTTAACTTCTTCTTGTCCTACAGCTAGCATG
 8  TCCACCACAACCACAGTAACAACTAGACTTATG
 9  GACCCAAAACTCATCAAGACCCATG
10  AACTCAACTTATTCATTTCACCTCACACATACAAAGAAAGAGAAAACGCTTTTATCCACTTAAATACTAGTAGTACTCATCAAAATG
11  AATCTGATCAAACCCTTCAACTTTTCCCAATAAGGAATG
12  GAGATCATG
13  GATG
14  CACTGATCATCATCATCATCATCATAACATTATCAAAGAGACACAGATATCAGCTTCAGCAATCAATG
15  CACCCAACCAGTTTATTGAGTTTCTTCCCTTGAAAAACTGA

sed apenas acrescenta uma nova linha após cada ocorrência da string ATG encontrada na entrada. sed também transforma linhas em branco para se parecer com:

::::::
::::

nl divide páginas lógicas na sua seção -d elimiter que está aqui definida como :: . Três seção -d elimitadores em uma linha por si só indicam o final de uma página lógica - que nl substitui por uma linha em branco - e duas são o início de uma nova. Eu começo cada contagem em -v0 zero porque a última seqüência em qualquer cadeia não conterá a string ATG .

Para uma saída menos descritiva, você pode simplesmente transformar cada ATG seqüência em um caractere que não aparece em sua entrada, e -d elete a diferença.

xsel |
sed 's/ATG/./g' | tr -dc . | wc -c

... que troca todos os ATG na entrada com um ponto, exclui todos os bytes que não são pontos e depois conta bytes:

24
    
por 22.09.2015 / 06:22

Tags