13 de enero de 2012

Construir un suffix array: Manber y Myers

Hola,
hoy me gustaría volver un poco sobre el tema de los suffix array que ya ha sido tratado alguna vez en el blog.

En 1990, Manber y Myers publicaban Suffix arrays: a new method for on-line string searches, como motivo del primer ACM-SIAM symposium on Discrete algorithms. En éste fantástico e ilustrativo artículo, introducen la comparación de esta estructura con los suffix trees y proponen definiciones, notación y algoritmos para su construcción, búsqueda y optimización.

La mayor desventaja de suffix trees reside en el espacio requerido, y con los suffix arrays se consigue reducir considerablemente, siendo aún así competitivos frente a los suffix trees en términos de búsqueda y construcción.

Aquí veremos la primera parte, la creación de un suffix array ordenado (sección 3 del artículo original, sorprendentemente), con un algoritmo que requiere O(NlogN) como peor caso, si bien con optimizaciones se podría conseguir un tiempo esperado O(N); lo cual ya se consiguió de manera formal en 2003.

Quizás hoy día los suffix array van perdiendo protagonismo de primera plana, pero siguen siendo la base para muchas aplicaciones, por ejemplo implicados en métodos de obtención de la secuencia Barrows-Wheeler. Posiblemente en entradas posteriores hablemos de mejoras en el uso de suffix arrays y de otras estructuras relacionadas como FM-index y BWT.

Por ahora, aquí os dejo el código en Python (-V 2.6.6). Podéis cambiar la secuencia a indexar en la variable inicial A.

Y nos podemos preguntar ¿por qué usar éste código en lugar de la simple línea de ordenamiento MergeSort que aparecía en el código Perl de la entrada anterior sobre suffix arrays? Adjunto una tabla que lo explica en términos de tiempo requerido para la construcción del índice.


Long texto Myers MergeSort
20 0''019 0''004
100 0''023 0''005
1,000 0''055 0''013
11,000 0''717 0''401
110,000 22''200 41''075
220,000 1'36''004 2'42''189
660,000 9'31''297 25'54''598


Por supuesto estamos espectantes ante cualquier comentario, crítica o sugerencia.
¡Un saludo!

 #!/usr/bin/python

# Simple algorithm for Suffix Array creation,
# based on Manber & Myers, 1990
# by Cantalapiedra, 2011

############### FUNCTIONS ##############
## Function to print a Suffix Array
def printSA(text, sa = [], sa_name = "Suffix Array"):
  if len(sa) == 0:
       print "No records in {0}".format(sa_name)
  else:
       print sa_name
       for i in sa:
            print "{0}\t{1}".format(i, text[i:])
  print "\n"
  return

## Function to print one or several lists
def printTemp(things = [], title = "##", post_title = "#"):
  if len(things) == 0:
       print "No things to print"
  else:
       print title
       for a in things:
            print a
       print post_title
  print "\n"
  return

############### VARIABLES ##############

A = 'TTTTAGATCGATCGACTAGA$'

pos = [] # Contains the SA based on suffix numbers (SN)
prm = [] # Inverse of pos, each position is a SN containing its position in SA
bH = [] # Boolean array marking the buckets

b2H = [] # Temporary array for marking the 2H-buckets
count = [] # Counts the number of SN in a 2H-bucket

## All above variables have length = |A|

################ START ###################
# Some verbose
print "Your text is {0}\n".format(A[:len(A) - 1])

# Initial SA (POS)
pos = [(a,i) for i,a in enumerate(A)]
pos = sorted(pos)
pos = [a[1] for a in pos]

printSA(A, pos, "INITIAL SA")

# Initialize PRM
prm = [0]*len(A)

# Initial positions and buckets
prev_letter = ""
for i, pos_i in enumerate(pos):
  prm[pos_i] = i

  letter = A[pos_i]
  if letter != prev_letter:
       bH.append(1)
  else:
       bH.append(0)
  prev_letter = letter

######### H-STAGES ##########

count_changed = []

h_stage = 1
while h_stage < len(A): # max log2(|A| + 1)

  #print "stage {1} init {0}".format(time.time(), h_stage) IMPORT time module to use this

  # FIRST: re-assign prm as of buckets starting points
  #            and create count and b2H arrays
  prev_one = 0

  for i, bh_i in enumerate(bH):
       if bh_i == 1:
            prev_one = i # Is a bucket starting position
     
       if bh_i == 0:
            prm[pos[i]] = prev_one # Points to its bucket starting pos
     
       count.append(0)
       b2H.append(0)

  # Reset count[] to 0s
  for a in range(len(count)):
       count[a] = 0

  # THEN: for every bucket...
  # Here the entire SA is scanned, but in fact takes account
  # of the current bucket being covered
  prev_count = [a for a in count]
  for i, pos_i in enumerate(pos):
     
       if bH[i] == 1:
            b2H[i] = 1
     
       # We are moving the H-prefix (Ti) of suffix in i position
       ti = pos_i - h_stage
       if ti < 0: continue
     
       ### This is the heart of the algorithm
       # If its the first change of this bucket during this H-bucket run...
       if prev_count[prm[ti]] == count[prm[ti]]:
            change = True
       else:
            change = False
     
       count[prm[ti]] += 1
       count_changed.append(prm[ti])
       prm[ti] = prm[ti] + count[prm[ti]] - 1
     
       # ... that means this is a new 2H-bucket
       if change:
            b2H[prm[ti]] = 1
     
       #printTemp([prm, count, b2H], "After moving suff: {0}".format(ti), "")
     
       # If next position is another H-bucket, or is the last bucket
       if (i < len(bH) - 1 and bH[i + 1] == 1) or i == len(bH) - 1:
          
            #printTemp([prm, count, b2H], "", "NEXT H-BUCKET {0}".format(i + 1))
          
            for j in count_changed:
                 prev_count[j] = count[j]
            count_changed = []
     
       # If there are no buckets left
       if 0 not in b2H:
            break

  #print "end stage {0}".format(time.time())

  # If there are no buckets left
  if 0 not in b2H:
       break

  #printTemp([prm, count, b2H], "", "NEXT ROUND {0}".format(h_stage*2))

  # Update POS from PRM
  for j, prm_j in enumerate(prm):
       pos[prm_j] = j

  # Update BH from B2H
  bH = b2H

  # Reset vars for next H-STAGE
  count = []
  b2H = []
  h_stage *= 2

# Update POS from PRM
for j, prm_j in enumerate(prm):
  pos[prm_j] = j

printSA(A, pos, "FINAL SA")
#


La salida del ejemplo es:

Your text is TTTTAGATCGATCGACTAGA

INITIAL SA
$
AGATCGATCGACTAGA$
ATCGATCGACTAGA$
ATCGACTAGA$
ACTAGA$
AGA$
A$
CGATCGACTAGA$
CGACTAGA$
CTAGA$
GATCGATCGACTAGA$
GATCGACTAGA$
GACTAGA$
GA$
TTTTAGATCGATCGACTAGA$
TTTAGATCGATCGACTAGA$
TTAGATCGATCGACTAGA$
TAGATCGATCGACTAGA$
TCGATCGACTAGA$
TCGACTAGA$
TAGA$

FINAL SA
$
A$
ACTAGA$
AGA$
AGATCGATCGACTAGA$
ATCGACTAGA$
ATCGATCGACTAGA$
CGACTAGA$
CGATCGACTAGA$
CTAGA$
GA$
GACTAGA$
GATCGACTAGA$
GATCGATCGACTAGA$
TAGA$
TAGATCGATCGACTAGA$
TCGACTAGA$
TCGATCGACTAGA$
TTAGATCGATCGACTAGA$
TTTAGATCGATCGACTAGA$
TTTTAGATCGATCGACTAGA$

29 de diciembre de 2011

Jornadas Bioinformáticas JBI 2012 (XI Edición)

Aprovecho esta última entrada del año para dar difusión a las Jornadas de Bioinformática JBI 2012. Como muchos sabréis, este congreso es el principal punto de encuentro anual de nuestra comunidad en la península ibérica, así que nuestro laboratorio también estará en Barcelona del 23 al 25 de Enero. El programa completo de las jornadas se puede descargar en este enlace.
http://sgu.bioinfo.cipf.es/jbi2012


Este año presentaremos parte de nuestro trabajo reciente:

"Genome-wide clustering of transcription factors by comparison of predicted protein-DNA interfaces"

donde explicamos y evaluamos la anotación de interfaces de reconocimiento de DNA en secuencias de proteínas por medio de diferentes aproximaciones como BLAST, TFmodeller, DP-Bind y DISIS.






El tema principal de las jornadas será "Arquitectura genómica, anotación y diseño", sobre el cual se discutirán los diferentes avances en la integración de los campos de la Biología, Medicina e Informática en el campo de la Genómica. Además se tratarán los siguientes temas:
- Análisis de datos de secuenciación de alto rendimiento (NGS)
- Bioinformática estructural
- Algoritmos de biología computacional y computación de alto rendimiento
- Análisis de sequencias, filogenética y evolución
- Bases de datos, herramientas y tecnologías en biología computacional
- Bioinformática en transcriptómica y proteómica
- Biología de sistemas

ENGLISH:

The XIth Spanish Symposium on Bioinformatics (JBI2012) will take place in January 23-25, 2012 in Barcelona, Spain. Co-organised by the Spanish Institut of Bioinformatics and the Portuguese Bioinformatics Network and hosted by the Barcelona Biomedical Research Park (PRBB). The full program can be downloaded from this link.

This year, the reference topic is “Genome Architecture, Annotation and Design” for which the conference will provide the opportunity to discuss the state of the art for the integration of the fields of biology, medicine and informatics. We invite you to submit your work and share your experiences in the following topics of interest including, but not limited to:

- Analysis of high throughput data  (NGS)
- Structural Bioinformatics
- Algorithms for computational biology and HPC
- Sequence analysis, phylogenetics and evolution
- Databases, Tools and technologies for computational biology
-  Bioinformatics in Transcriptomics and Proteomics
- System and Synthetic Biology

Our contribution to the congress:

Genome-wide clustering of transcription factors by comparison of predicted protein-DNA interfaces

Transcription Factors (TFs) play a central role in gene regulation by binding to DNA target sequences, mostly in promoter regions. However, even for the best annotated genomes, only a fraction of these critical proteins have been experimentally characterized and linked to some of their target sites. The dimension of this problem increases in multicellular organisms, which tend to have large collections of TFs, sometimes with redundant roles, that result of whole-genome duplication events and lineage-specific expansions. In this work we set to study the repertoire of Arabidopsis thaliana TFs from the perspective of their predicted interfaces, to evaluate the degree of DNA-binding redundancy at a genome scale. First, we critically compare the performance of a variety of methods that predict the interface residues of DNA-binding proteins, those responsible for specific recognition, and measure their sensitivity and specificity. Second, we apply the best predictors to the complete A.thaliana repertoire and build clusters of transcription factors with similar interfaces. Finally, we use our in-house footprintDB to benchmark to what extent TFs in the same cluster specifically bind to similar DNA sites. Our results indicate that there is substantial overlap of DNA binding specificities in most TF families. This observation supports the use of interface predictions to construct reduced representation of TF sets with common DNA binding preferences.


23 de diciembre de 2011

Felices Navidades bioinformáticas!!!

Ya que estamos en Navidad os dejo nuestra felicitación navideña especialmente pensada para los bioinformáticos... con algo de inspiración en estructura tridimensional de proteínas y dianas terapéuticas.

Adjunto la imagen a alta resolución para que podáis intentar adivinar con qué estructura del PDB se han generado las bolas (proteínas) y adornos (ligandos) que decoran el árbol, dejar en los comentarios vuestras respuestas...

Y por supuesto... FELIZ NAVIDAD Y PRÓSPERO AÑO 2012!!!

English version:

In this Christmas time we want to share our Christmas card especially designed for bioinformaticians ... with some inspiration from three-dimensional structure of proteins and therapeutic targets.

It is a high resolution image so you can try to guess from which PDB structure have been extracted the balls (proteins) and ornaments (ligands) that decorate the tree, give your answers in the comment section ...

And of course... MERRY CHRISTMAS AND HAPPY NEW YEAR 2012!!!









19 de diciembre de 2011

metaDBSite: un metaservidor para predecir la unión de proteínas a DNA

Los meta-servidores son valiosas herramientas en bioinformática para no perder el tiempo mandando trabajos a diferentes servidores y tener que juntar después manualmente los resultados. Un meta-servidor nos ofrece utilizar varios servicios web a la vez desde una interfaz única. Ejemplos de meta-servidores son: NCBI, UniProt, GeneSilico...

Recientemente he  tenido que usar diferentes programas de predicción de interfaces de unión proteína-DNA, y he encontrado la grata sorpresa de que existía un meta-servidor que permitía realizar la predicción de una sola vez utilizando la mayoría de técnicas conocidas, este valioso meta-servidor se llama metaDBSite. No sólo eso, si no que he podido comprobar que siguen dándole soporte.

Os animo a probarlo con una sencilla secuencia proteica:
>1a02_N  
 wplssqsgsyelrievqpkphhRahYetEgsRgavkaptgghpvvqlhgymenkplglqifigtaderilkphafyqvhritgktvtttsyekivgntkvleiplepknnmratidcagilklrnadielrkgetdigRkntrvrlvfrvhipessgrivslqtasnpiecsQRsahelpmverqdtdsclvyggqqmiltgqnftseskvvftekttdgqqiwemeatvdkdksqpnmlfveipeyrnkhirtpvkvnfyvingkrkrsqpqhftyhpv  

Si comprobáis los resultados con los datos de la estructura original (cadena N de la estructura 1a02) podréis ver cómo el mejor de los métodos (BindN-RF) 'adivina' 7 de los 7 residuos que contactan el DNA entre los 18 predichos, si tenemos en cuenta que la proteína tienen 280 aminoácidos, el resultado no está nada mal...




12 de diciembre de 2011

Sincronizando el Protein Data Bank

Hola,
para los que trabajamos de manera habitual con archivos del Protein Data Bank es muy conveniente tener acceso a la colección de estructuras en formato PDB. Ojo, necesitarás al menos unos 14Gb de disco, pero tendrás al  alcance de tu mano más de 77 mil estructuras de proteínas (y sus ligandos). La sección de descargas del PDB ofrece varias opciones, pero en mi opinión, si necesitas acceder desde tus programas a los archivos PDB sin supervisión, lo más eficiente es tener una copia local, lo que en la jerga se llama mirror o sitio espejo. Como el PDB se va actualizando semanalmente y no sólo se añaden entradas nuevas, si no que se van corrigiendo o completando estructuras antiguas, el proceso de sincronización no es tan sencillo como pudiera parecer. Es aquí donde nos salva la vida el software rsync, parte integrante de cualquier Linux moderno, que permite hacer estas actualizaciones de manera eficiente, y que fácilmente podemos añadir a un cron semanal:

 #!/usr/bin/perl -w   
 use strict;  
   
 my $PDBSERVER = 'rsync.wwpdb.org';  
 my $PDBPORT  = 33444;  
 my $LOCALPDBDIR = '/path/to/my/PDB/mirror/';  
 my $LOGFILE   = '/path/to/PDBmirror.log';  
   
 my $rsync_command = "/usr/bin/rsync -rlpt -v -z --delete --exclude=biounit ".  
      "--exclude=monomers --exclude=status --exclude=obsolete --exclude=models ".  
      "--exclude=mmCIF --exclude=nmr_restraints* --exclude=structure_factors " .  
   "--exclude=XML --exclude=XML-extatom --exclude=XML-noatom ".  
      "--port=$PDBPORT $PDBSERVER\::ftp_data/ $LOCALPDBDIR";  
   
 open(LOG,">$LOGFILE") || die "# $0 : cannot write to $LOGFILE\n";  
 open(RSYNC,"$rsync_command 2>&1 |") || die "# $0 : cannot execute $rsync_command\n";  
 while(<RSYNC>)  
 {  
   print LOG;   
   if(/rsync: failed to connect to/)  
   {  
       die "# $0 : error:\n$_\n";  
   }  
 }  
 close(RSYNC);  
 close(LOG);  

Un saludo, Bruno