Thème: Génomique et Analyse de séquences biologiques (Semaines 6 à 7) L'analyse des séquences biologiques a connu ces dix dernières années un essor considérable avec l’apparition du séquençage massif d'organismes, et de grandes bases de données génomiques. L’exploitation de ces gigantesques bases a motivé le développement de modèles mathématiques ou informatiques pour l’analyse automatique de ces séquences. Après une présentation des principales macromolécules biologiques et leur fonction dans la cellule, ce cours décrit les méthodes et les outils les plus communément utilisés pour analyser les séquences biologiques : recherche de signaux et de zones codantes, techniques d’alignement (programmation dynamique), recherche de similarités locales entre séquences. L’utilisation de ces outils sera illustrée sur des problèmes types comme la comparaison de séquences, la recherche d’homologies, la prédiction. Différents programmes d’analyse sont aujourd’hui accessibles par le web et seront utilisés aux TP. Le cours illustrera quelques-uns des développements informatiques nouveaux nécessaires au traitement et à la manipulation des données correspondantes. PréTP (initiation à python) (note: passer sous tcsh au CICRP !!!) Générer un tableau de distance entre villes (plusieurs catégories de villes) Programmation dynamique – Camions (tranches) Présentation du langage Python – langage interprété interactif Variables: type implicite liste, tuple et string sont des séquences. Indentation délimite les blocs d'instructions – instruction vide "pass" Listes: a = [] # déclaration d'une liste Les listes commencent à 0, coordonnées négatives == permutations circulaires –1 == dernière case (maximum négatif = -longueur, dernière case +1 : erreur,, types différents autorisés. Donc les coordonnées vont de –longueur à +(longueur –1) >>> a.append(3) >>> a.append("toto") >>> a.append("tutu") >>> a.append("titi") >>> a [3, 'toto','tutu','titi'] a[1:3] # extrait sous liste éléments 1 à 3 ['toto','tutu'] a = {} # création d'un tableau associatif qui peut être indexé par string, entier ou tuple a["toto"] = "TITI" a[("toto","titi")] = "TOTOTITI" a[("toto","tutu")] = "TOTOTUTU" for i in liste: # i prend successivement les valeurs de la liste for i in xrange(debut, fin, step): # i prend les valeurs de "debut à ("fin"-1) par pas de "step". >>> for i in xrange(1,6,2): ... print i ... 1 3 5 while <test> : def foo(arguments): # indentation nécessaire def plus(a,b): return a+b def carre(a): return a*a liste=range(4) liste [0, 1, 2, 3] # lister les methodes liees a un objet dir(liste) ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__eq__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__repr__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__str__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] reduce(plus,liste) # f(f(f(liste[0],liste[1]),liste[2]), liste[3])..etc 6 map(carre,liste) [0, 1, 4, 9] map(plus, liste,liste) [0, 2, 4, 6] map(None, liste1,liste2): applique None aux doublets d'une liste constituée de chacune des paires des éléments de liste1 et liste2 filter(f,liste): retourne la sous liste de liste constituée de chacun des éléments pour lesquels f est vraie. ## Lecture fichiers: >>>f=open('nom_fichier','r') # ouvre le fichier en lecture avec descripteur f >>>l=f.readlines() # lit toutes les lignes et crée une liste ## Ecriture fichiers: f=open("nom_fichier","w") f.write("%d %f " % (1, random.random())) ## Librairie "string" >>>import string >>>l = "toto titi tutu" >>> string.split(l) ['toto', 'titi', 'tutu'] ## Nombres aléatoires >>> import random >>> random.random() 0.0119499521299 # préparation du fichier de villes g=open("villes","w") lv=string.split("a b1 b2 b3 b4 c1 c2 c3 c4 d1 d2 d3 e1 e2 e3 e4 e f1 f2 f3 g") c={} c["a"]=1 c["b"]=2 c["c"]=3 c["d"]=4 c["e"]=5 c["f"]=6 c["g"]=7 for x in lv: for y in lv: if c[x[0]]==c[y[0]]-1: g.write("%s %s %f " % (x,y,int(100*random.random())) g.close() bubble, mergesort ouvrir un texte (nedit) pour le programme "tri.py" import tri # la première fois reload(tri) # les autres fois import random # création du fichier de nombres aléatoires f=open("random","w") i = 0 while i < 100: f.write("%d %f " % (i, random.random())) i=i+1 f.close() f=open("random","r") # lecture du fichier de nombres aléatoires ll=f.readline() # ll est une string avec toutes les valeurs t=[] # création du tableau de valeurs for x in string.split(ll): t.append(string.atof(x)) Excercice: programmation dynamique camions (programmation dynamique). liens avec les séquences fichier "lv" paris lyon 23 paris dijon 32 paris clermont 29 paris bordeaux 34 lyon valence 13 dijon valence 34 clermont valence 29 bordeaux valence 22 lyon cahors 22 dijon cahors 14 clermont cahors 19 bordeaux cahors 17 lyon millau 22 dijon millau 16 clermont millau 23 bordeaux millau 19 valence marseille 21 cahors marseille 27 millau marseille 18 #!/usr/local/bin/python2.1 import string import copy def camion(): f=open('lv','r') lignes=f.readlines() # lignes: liste de string t=[] for l in lignes: t.append(string.split(l)) distance={} for i in t: distance[(i[0],i[1])]=int(i[2]) print distance tranche=[] vd=string.split(l[0])[0] tranche=[[vd]] print tranche courant=tranche[0] while len(courant)!=0: tmp=[] for x in distance.keys(): if x[0]==courant[0]: tmp.append(x[1]) if len(tmp)!=0: tranche.append(tmp) courant=tmp print tranche chemin=[(0,[vd])] for x in tranche[1:]: # x: tranches successives newchem=[] for k in x: # k: villes successives mini=distance[(chemin[0][1][-1],k)]+chemin[0][0] for z in chemin: # z: chemins successifs if (distance[(z[1][-1],k)]+z[0]<=mini): mini=distance[(z[1][-1],k)]+z[0] y=copy.deepcopy(z) y[1].append(k) newchem.append((mini,y[1])) chemin=newchem print newchem Cours 1 (2 heures): 1ère partie: le problème biologique (1h15) Cellules procaryotes et eucaryotes : différences, ressemblances, chromosomes, machinerie cellulaire Les macromolécules biologiques (polymères), structure, forme et information : reconnaissance moléculaire (acides nucléiques, protéines), localisation cellulaire, fonctions. Mécanismes génétiques fondamentaux : - ADN support de l'information génétique : structure de l'ADN, - polymère de nucléotides - double hélice complémentaire, orientation des brins réplication de l'ADN réparation de l'ADN, mutations, mécanismes de la recombinaison génétique, sélection, évolution - ARN (ARM messagers et ARN de transfert) transcription, expression de l'information génétique - Synthèse protéique : traduction, code génétique, codage. Protéines: structure primaire, structure secondaire, structure tertiaire, structure quaternaire. Le passage du gène à la protéine se fait en deux étapes : tout d'abord le segment de la molécule d'ADN correspondant au gène est copié sur un brin d'ARN, que l'on appelle ARN messager (ou ARNm), c'est la transcription. Puis ce brin d'ARNm est à son tour recopié, mais dans un langage différent, celui des acides aminés, pour donner la séquence correspondant à la protéine synthétisée, c'est la traduction. La séquence polypeptidique ainsi constituée prend alors une forme spatiale qui lui est spécifique pour devenir à proprement parler la protéine. D'un point de vue plus formel, ces deux étapes sont très différentes. En effet pour la première on garde le même alphabet, il s'agit donc simplement d'une recopie du gène. Cette recopie a essentiellement deux intérêts : elle permet de recopier le gène sur un seul brin, forme certes moins stable mais qui rendra plus simple le processus de traduction. En outre, chez les cellules eucaryotes, seul l'ARNm se déplace hors du noyau ce qui protège la molécule d'ADN. L'étape de recopie peut donc être vue comme une préservation de la molécule d'ADN, vitale pour la cellule. La seconde étape, par contre, est une vraie traduction car on passe de l'alphabet à quatre lettres de l'ADN à l'alphabet à vingt lettres des acides aminés. Voyons à présent plus en détail ces deux étapes. Comme nous l'avons déjà évoqué plus haut, l'étape de transcription consiste en la recopie d'un segment de brin d'ADN sur une molécule d'ARNm. Cette recopie se fait par l'intermédiaire d'une enzyme appelée ARN-polymérase. Les fonctions de cette enzyme sont multiples. Tout d'abord, elle doit reconnaître le commencement du gène portant l'information permettant de synthétiser la protéine voulue. Ceci se fait grâce à un site spécifique sur la molécule d'ADN appelé promoteur, qui se situe juste avant le début du gène. Un promoteur typique comporte une soixantaine de paires de base. Une fois que la polymérase s'est liée au promoteur, elle commence la transcription du gène : elle ouvre d'abord la double hélice (au niveau des liaisons hydrogène qui sont des liaisons faibles) puis elle avance le long d'un des deux brins en synthétisant au fur et à mesure le brin complémentaire. Arrivée à la fin du gène, une séquence spécifique provoque le détachement de la polymérase et le brin d'ARN ainsi construit est libéré. La molécule d'ARNm ainsi constituée sort ensuite du noyau (chez les cellules eucaryotes) pour subir l'étape de traduction dans le milieu intracellulaire. L'alphabet utilisé reste identique, mis-à-part la base T qui est remplacée par l'uracile U. Selon la polarité de la molécule d'ADN, le brin recopié ainsi que le sens de recopie sont fixés pour chaque gène. Notons ici que la transcription est dans les faits plus complexe car elle est suivie d'autres traitements, qui ne retiennent du gène que sa partie effectivement codante (on parle d'épissage) La traduction est une étape légèrement plus complexe, au moins d'un point de vue formel, car il s'agit de passer de l'alphabet à quatre lettres à l'alphabet des acides aminés qui sont plus d'une vingtaine. Il faut donc plusieurs bases pour pouvoir coder un acide aminé. Un rapide calcul montre qu'utiliser des triplets de bases suffit à tous les déterminer. On code alors 43=64 mots ou codons, ce qui implique que ce codage est redondant. Figure : schéma simplifié de la traduction La traduction se déroule dans le milieu intracellulaire, grâce à des agents appelés ribosomes. l'ARN messager est lu par le ribosome qui associe à chaque codon, par l'intermédiaire d'une molécule d'ARN particulière (l'ARN de transfert), l'acide aminé qui lui correspond. La chaîne polypeptidique ainsi constituée subit à son tour quelques traitements (dont la prise de sa forme, souvent très complexe) pour devenir la protéine désirée.. Le Code Génétique Universel | T | C | A | G | --+-------------+-------------+-------------+-------------+-| TTT Phe F | TCT Ser S | TAT Tyr Y | TGT Cys C |T T | TTC Phe F | TCC Ser S | TAC Tyr Y | TGC Cys C |C | TTA Leu L | TCA Ser S | TAA Stop | TGA Stop |A | TTG Leu L | TCG Ser S | TAG Stop | TGG Trp W |G --+-------------+-------------+-------------+-------------+-| CTT Leu L | CCT Pro P | CAT His H | CGT Arg R |T C | CTC Leu L | CCC Pro P | CAC His H | CGC Arg R |C | CTA Leu L | CCA Pro P | CAA Gln Q | CGA Arg R |A | CTG Leu L | CCG Pro P | CAG Gln Q | CGG Arg R |G --+-------------+-------------+-------------+-------------+-| ATT Ile I | ACT Thr T | AAT Asn N | AGT Ser S |T A | ATC Ile I | ACC Thr T | AAC Asn N | AGC Ser S |C | ATA Ile I | ACA Thr T | AAA Lys K | AGA Arg R |A | AUG Met M | ACG Thr T | AAG Lys K | AGG Arg R |G --+-------------+-------------+-------------+-------------+-| GTT Val V | GCT Ala A | GAT Asp D | GGT Gly G |T G | GTC Val V | GCC Ala A | GAC Asp D | GGC Gly G |C | GTA Val V | GCA Ala A | GAA Glu E | GGA Gly G |A | GTG Val V | GCG Ala A | GAG Glu E | GGG Gly G |G --+-------------+-------------+-------------+-------------+-- Dogme central: ADN -> ARN -> Protéines Organisation fonctionnelle de l'ADN : - taille des génomes (procaryotes, eucaryotes) : nombres de gènes, pourcentage de codant. - gènes (procaryotes, eucaryotes), opérons - synthèse et maturation de l'ARN, éléments de base dans le contrôle de l'expression génique (CAT box, TATA box, terminateurs), mécanismes de régulation des gènes. Analyse des génomes – annotation : Le problème crucial de l'analyse de séquences génomiques est l'identification des séquences codantes (processus d'annotation). Chez les procaryotes, cette identification est grandement facilitée par la quasi absence de séquences non codantes et l'absence d'introns, et par la possibilité de reconnaître assez facilement les phases ouvertes de lecture, les promoteurs et les terminaisons des gènes. Chez les bactéries E. coli ou H. influenzae, plus de 85% du génome est transcrit. De plus, des signaux indicateurs de gènes existent souvent chez les procaryotes (ex: RBS ribosome binding site, sequence Shine-Dalgarno, TATA box, boite de Pribnov). Deux caractéristiques compliquent radicalement l'identification des séquences codantes chez les eucaryotes : le découpage des gènes en introns et exons, et la présence de régions intergéniques parfois très vastes (et les répétitions, LINE: "long interspersed elements", SINE: "short interspersed elements"). Organisme Nombre de gènes % de codant taille (Kb) Procaryote Mycoplasma genitalium 580 480 91 Helicobacter pilori 1668 ~1600 91 Bacillus subtilis E. coli Eucaryotes S. cerevisiaie (levure) C. elegans H. sapiens 4215 4639 ~4000 ~4300 86 88 13 Mb (16 chromosomes) ~100 Mb ~3Gb ~6400 ~18000 ~30000 70 <5 L'identification des unités transcriptionnelles reste possible grâce à des outils informatiques capables d'identifier un gène sur plusieurs critères : la présence d'une phase ouverte de lecture, de signaux d'épissage, la composition en bases. On utilise aussi pour déterminer si une séquence est codante la comparaison à l'ensemble des données acquises par les programmes de séquençage d'ADN. Une similarité entre une séquence génomique et une séquence ADNc permet de conclure que cette séquence est transcrite (voir la recherche sur banque). On utilise l'information à priori concernant l'organisme pour identifier les gènes et l'organisation des chromosomes : usage des mono et dinucléotides, biais de codage, biais dans l'usage du code (recstat, codon preference). Banques de séquences: Il existe de nombreuses banques de séquences : il s'agit de base "à plat" (les séquences sont à la suite les unes des autres, des identificateurs existent en début de ligne. SwissProt : banque "propre" de séquences protéiques (environ 100 000 séquences en 2000) EMBL/GenBank: banque de séquence nucléiques (106 séquences). TrEMBL/Genpept : séquences protéiques transcrites de GenBank. PIR: banque protéique NR: "non redondante", assemblage de Swissprot, Genpept + PIR Autres banques : Prosite: banque de motifs biologiques (famille) PRODOM: banque de domaines associés à des familles PDB: banque de structures cristallographiques/RMN (environ 6000 structures en 2000, mais trsè redondant (environ 100 lysozymes, dont beaucoup de mutants ponctuels dont la structure 3D ne change pas). 2ème partie: formalisation de quelques problèmes de reconnaissance Recherche de signaux : 2 types : - recherche de pattern (motif): ex: recherche de promoteurs de la transcription (CAT ou TATA box), Ribosome binding site (RBS) - recherche de "consensus" : matrice score position / Bayes Recherche de signaux: On utilise des algorithmes courants sur les chaînes de caractères (Boyer-More, Aho Corasick) et les expressions régulières. Matrice de poids score-position (PSSM): La méthode [Trifonov, 1985] consiste à définir, à partir d'un lot de séquences alignées, une matrice de poids décrivant, en chaque position, la fréquence d'apparition de chaque type de résidus dans l'alignement multiple. On cherche ensuite des signaux potentiels sur une nouvelle séquence en appliquant la matrice considérée sur une fenêtre glissant le long de la séquence. A chaque pas, on calcule un score égal à la somme des poids associés aux résidus délimités par la fenêtre, en fonction de leur nature et de la position consensus que l'on considère. Pour ce qui est de la détection de signaux sur des séquences protéiques cette méthode souffre du fait qu'elle ne permet pas de considérer les relations de proximité entre acides aminés (voir prochain cours sur les système de score et les matrices de substitution entre acides aminés). Gribskov et collaborateurs proposent une méthode également fondée sur la définition d'une matrice de poids, mais permettant en plus la prise en compte d'une matrice de distance entre acides aminés [Gribskov et coll., 1987]. Cette matrice de poids est appelée "profile" ou "position-specific scoring matrix" (PSSM), un terme équivalent étant le terme "position-dependent weight matrix". Une PSSM consiste en plusieurs colonnes de scores pour chaque aminoacide, dérivées des positions correspondantes d'un alignement multiple (une colonne peut aussi inclure un score pour un gap). Un "profile" est une PSSM construite en utilisant la moyenne des scores. Le calcul du score d'une position d'une PSSM est basée sur les probabilités de Bayes (rappel: P(A et B) = P(A/B)*P(B) = P(B/A)*P(A)). Pour chaque "morceau" de la séquence examinée, on veut que le score représente la probabilité d'avoir une instance du motif cherché étant donnée ce "morceau" de séquence, donc P(motif/séquence). Or ce qu'on aurait dans la matrice fréquence/position (qui serait calculée directement à partir de l'alignement multiple qui représente le motif), c'est exactement la probabilité symétrique, c'est à dire la probabilité d'avoir la séquence si on est dans une instance du motif, donc P(séquence/motif). Le théorème de Bayes nous permet de tirer la probabilité cherchée P(motif/séquence) à partir de la probabilité P(séquence/motif). Méthode : on peut facilement à partir d'un alignement multiple générer les fréquences associées à chacun des acides aminés à chacune des positions dans une matrice 20 * longueur du motif (20: nombre des acides aminés). Cette matrice représente les probabilité d'avoir tel ou tel acide aminé à telle position si on a un motif, donc P(séquence/motif). Vu qu'on cherche P(motif/séquence), en utilisant Bayes, on obtient: P( séquence | motif ) × P( motif ) P( motif | séquence) = P( séquence) Si on suppose l'indépendance des positions successives, on peut écrire: P( séquence) = ∏ P( aai ) i et P( séquence | motif ) = ∏ P( aai | motif ) i avec P(aai) probabilité dans la banque du i-ème acide aminé de la séquence Donc, on obtient: ∏i P(aai | motif ) × P(motif ) P(aai | motif ) = ∏ P( motif | séquence) = × P( motif ) P( aai ) i ∏ P(aai ) i On retrouve bien le fait que si les acides aminés constituant la séquence du motif sont très abondants dans la banque de séquence - i.e. les P(aa(i)) sont grands - cela réduira d'autant la probabilité d'avoir effectivement un motif si on trouve une séquence ressemblant à celle du motif. On ne connaît pas a priori la probabilité du motif (ce n'est pas très grave dans la mesure où elle sera la même, quelle que soit la région considérée). Par contre, on connaît les P(aa(i)/motif), c'est la fréquence (entre 0 et 1) de l'acide aminé à la position i dans le motif (dans les séquences pré-alignées qui nous ont servi à caractériser ce motif). De même, on connaît P(aa(i)), c'est la probabilité d'avoir l'acide aminé sur toutes les séquences (fréquence de aa(i) dans la séquence examinée, ou dans la banque). Comme indiqué ci dessus, on va prendre comme score P(motif/aa(i)) = P(aa(i)/motif)/P(aa(i)), ce qui revient à pondérer la fréquence de l'acide aminé dans la colonne de l'alignement par sa fréquence dans la banque. Le score associé à une position sur une séquence examinée sera donc le produit des P(motif/aa(i)) (ou la somme des log). Note: il faudra éventuellement s'arranger pour ne pas avoir de P(motif/aa(i)) égal à 0, sinon dès qu'un acide aminé présent sur la séquence n'est pas du tout présent dans la colonne correspondante de l'alignement, P(motif/séquence) sera nul, même si les acides aminés à côté de celui ci sont tous présents dans le motif avec une grande probabilité (ceci peut être fait en utilisant une matrice de similarité avec laquelle on redistribuera la probabilité d'un acide aminé présent sur les autres acides aminés éventuellement absents grâce au score de similarité entre eux). Recherche de zones codantes (ce point sera détaillé au TD1): - méthodes statistiques : comptage de mots, chaînes de Markov, analyse factorielle, mesure du biais d'usage du code - apprentissage : réseaux neuronaux, Hidden Markov Model, caractérisation de site (RBS). (tous ces points ne seront pas traités en détail – cela dépendra du temps) Modèles de Markov, IMM (interpolated Markov Model) Les programmes d'annotation Genmark (Borodovski) et Glimmer (Salzberg) utilisent de tels modèles pour la détection de zones codantes. Rappel sur les chaînes de Markov: Processus de génération d'une séquence dans lequel on tient compte des états précédents pour "émettre" l'état courant. Ce modèle est utilisé en bioinformatique comme modèle de séquence aléatoire d'ADN (par exemple, comme modèle hypothèse nulle, H0, dans la détermination des mots sous ou sur-exprimés). L'ordre d'une chaîne de Markov est le nombre d'états précédents dont on a tenu compte pour émettre l'état courant. Ordre 0: indépendance des positions (P(X1X2) = P(X1)*P(X2) Ordre 1: P(X/X1) 42=16 paramètres P(A/A), P(A/G), P(A/C), P(A/T), P(C/A).... Ordre 2: P(X/X1X2) 43=64 paramètres P(A/AA), P(A/AC), P(A/AG),... Ordre k: 4k+1 paramètres Utilisation pour calculer la fréquence théorique des mots de taille m dans une séquence: on veut calculer P(X1X2...Xm) en tenant compte des fréquences connues des sous mots de taille k. Remarque : si m est la taille, le plus petit ordre k possible est m-2. mots de taille m=2 k = 0 P(X1X2)=P(X1)P(X2) fréquence des dinucléotides dans l'hypothèse d'indépendance des mononucléotides mots de taille m=3 k = 1 P(X1X2X3)= P(X1).P(X2/X1).P(X3/X2) or on a P(AB)=P(B/A).P(A) donc P(B/A) = P(AB)/P(A) d'où P(X1X2X3)= P(X1).P(X1X2)/P(X1).P(X3/X2)/P(X2) = P(X1X2).P(X2X3) / P(X2), fréquence des tri en tenant comte des di (et des monos). k = 0, P(X1X2X3)= P(X1).P(X2).P(X3) Le principe de calcul général est simple: - fixer les k premiers nucléotides P(X1...Xk) - rajouter (produit) les probas de transition suivantes P(Y/X1...Xk) - - utiliser la formule P(B/A) = P(AB)/P(A) pour simplifier m \ 0 (mono) 1 (di) 2 (tri) m-2 (m-1mère) ordre 2 P(X1).P(X2) P ( X X ). P ( X X ) 3 P(X1).P(X2).P(X3) 1 2 2 3 P( X 2 ) P( X1 X2 X3 ).P( X2 X3 X4 ) 4 P(X1).P(X2).P(X3).P(X4) P( X1 X2 ).P( X2 X3 ).P( X3 X4 ) P( X2 ).P( X3 ) P( X2 X3 ) m P( X1 X2 ).P( X2 X3 )....P( Xm −1 Xm ) P( X1 ... Xm −1 ).P m P( Xi ) ∏ P( X2 ).P( X3 )...P( Xm −1 ) P( X2 ... X i =1 Applications : Statistique sur les mots Permet de calculer E(Nw), l'espérance du nombre de mot w, w étant un mot X1...Xm . Note: le calcul de Var(Nw) est beaucoup plus compliqué (Schbath et al. JCB, 1995) Utilisation pour la détection de zones codantes: 2 étapes: - apprentissage sur des exemples de gènes (ex: longues ORF), c'est à dire estimation des probas de transition suivant différents ordres) - comparaison sur la séquence étudiée des fréquences observées à celles attendues. En général, le score est calculé sur une fenêtre glissante sur les 3 phases directes et les 3 phases inverses (puis normalisé à 1 sur l'ensemble des phases). Intérêt et problèmes: - - à l'heure actuelle, c'est la méthode la plus efficace pour procaryotes (et certains eucaryotes) utiliser l'ordre le plus élevé possible lorsque l'apprentissage est réalisé sur un grand ensemble (problème de l'évaluation des paramètres, il faut un nombre d'exemple suffisant d'exemple pour calculer les 4k paramètres) problème des classes d'expression des gènes (tous les gènes n'ont pas les mêmes fréquences d'apparition des mots) problème des gènes chevauchants Calcul des probabilités dans Genmark (Borodovski et al., Comp. Chem. 1993) : Fragment F = AGGCAT P(F) = P(AG).P(G/AG).P(C/GG).P(A/GC)... (pour un modèle de Markov d'ordre 2). En fait, ceci est calculé pour les 7 cas exclusifs suivants: Cod1 Cod2 Cod3 Cod-1 Cod-2 Cod-3 NonCod <--- codant 6 phases ---------------> Non codant Pour l'exemple plus haut, on a donc : F = A1G2G3C4A5T6 P(F/Cod1) = P01(AG).P1(G/AG).P2(C/GG).P3(A/CG).P1(T/CA)...(chaîne de Markov non homogène : périodique). Les Pi sont estimés sur les données d'apprentissage (matrice de transition (pour les 7 cas)). Par exemple, P1(G/AG) = N1AGG / N1x En réalité, on ne cherche pas P(F/Cod1) mais P(Cod1/F) (formule de Bayes) P(Cod1/F) = P(F/Cod1).P(Cod1)/∑P(F/Codi).P(Codi) (la somme est sur les 7 cas ci dessus, Cod1...-3 et NonCod). On peut prendre P(Cod1) = 1/7 ou tenir compte du % de codant de l'organisme. Dans les IMM ("interpolated markov models", programme Glimmer), la profondeur du modèle utilisé va dépendre de la région examinée. Par exemple, si on est dans un génome riche en bases A et T, le modèle de Markov utilisé dans la détection de gènes dans les zones AT riches sera d'ordre plus élevé que celui utilisé dans les régions GC riches (car on a évidemment plus d'exemples pour le créer). TD 1 / TP 1 (2 * 2h): Partie TP: recherche de régions codantes par chaînes de Markov (sur un brin). - système d'apprentissage (3 tables des mots phasés -> calcul des matrices de transition (ex: proba(T suivant A) pour un modèle d'ordre 1, calculé sur les mots de longueur 2, on prend ordre 0 pour le non-codant par exemple. Matrice de transition de 12 par 4^n, n étant l'ordre du modèle, 12 car 4 bases*3phases). - système d'évaluation des scores (calcul de la proba en appliquant la matrice avec une fenêtre glissante par pas de 3-> 3 probas -> application de Bayes (ex: procaryotes: 90% de codant)). Expressions régulières: métacaractères classiques : • . n’importe quel caractère • ? 0 ou 1 fois le caractère précédent • * 0 ou plusieurs fois le caractère précédent • + 1 ou plusieurs fois le caractère précédent (pas toujours présent selon le programme° o A+ équivaut à AA* • [] désigne une classe de caractères considérés comme équivalents. Dans les crochets deux caractères acquièrent une signification particulière : o – intervalle [0-9 A-Z] o ^nie une classe de caractères [^0-9] ne concorde avec aucun nombre • ^ début de ligne • $ fin de ligne ^$ concorde avec les lignes vides c’est-à-dire les lignes avec seulement un retour chariot (pas d’espace) • \ annule la signification du métacaractère suivant \\ correspond au caractère \ lui-même. Métacaractères des expression étendues • {} indique un certain nombre d’occurrences du caractère précédent b{2,5} correspond à bb, bbb,bbbb,bbbbb • () groupement d’expression vu avec le | qui signifie ou A(ATG|TTG)G signifie A sui vi de ATG ou TTG puis G Exercice : trouver une expression régulière qui permette de trouver les ORFs dans une séquence avec - commence par ATG, TTG, ou GTG - fini par TAA et TAG (TGA n'est pas un stop chez les mycoplasmes, mais un TRP) - entre les deux au moins 20 codons qui ne soient pas des stops. Correction: L’expression est la suivante : commence par ATG, TTG ou GTG: [ATG]TG au moins 20 codons "non stop": La seule difficulté est de donner le pattern pour « pas codon stop », donc ni TAA ni TAG. [^¨T] . . [^A] . T A[^AG] ([^T]..|T([^A].|A[^AG])){20,} un codon stop TAA ou TAG : TA[AG] d'où l'expression totale suivante : [ATG]TG([^T]..|T([^A].|A[^AG])){20,}TA[AG] Pour chercher sur la séquence complémentaire inversée (sans avoir à inverser-complémenter la séquence, on prend l'expression suivante (on commence par un stop complémentaire inversé, TTA ou CTA, puis par un non stop complémentaire inversé, puis on finit par un start complémentaire inversé (CAT, CAA ou CAC): ([AC]TA)(([AG]..)|([CT][^T].)|([CT]T[^A])){300,}CA[TAC] En fait, on peut "oublier" les stops pour ne pas les compter dans les statistiques. ## expr reguliere import re ##compile(fabrique l'automate): orf=re.compil('expre_reguliere') ##findall: list=re.findall(orf,seq) ##function de concaténation de chaines def concat(l): return reduce(lambda x,y:x+y,l).upper() ##lit et rend une sequence, ne pas oublier l'affectation devant def readseq(f): return concat(map(lambda x:x[0:-1],open(f).readlines())) ##passe une chaine 5-3 en une chaine 3-5 attention mauvaise complexité def reverse(l): l=list(l) l.reverse() return concat(l) ##passe d'un brin a l'autre def complement(l): return concat(map(lambda x:{"A":"T","G":"C","T":"A","C":"G"}[x],l)) ##associe complement et reverse sans les utiliser def antiparallele(l): l = map(lambda x:{"A":"T","G":"C","T":"A","C":"G"}[x],l) l.reverse() return concat(l) ##function findorf et rend une liste de string correspondant aux orf's def find_orf(seq): orf=re.compile('[ATG]TG(([^T]..)|(T[^A].)|(TA[CT])){300,}') orfc=re.compile('(([AG]..)|([CT][^T].)|([CT]T[^A])){300,}CA[TAC]') m=re.search(orf,seq) mc=re.search(orfc,seq) fin=m.end(0) finc=mc.end(0) l_orf=[] l_orfc=[] while (m): l_orf.append(m.group(0)) fin=fin+m.end(0)+1 m=re.search(orf,seq[fin:]) while (mc): l_orfc.append(mc.group(0)) finc=finc+mc.end(0)+1 mc=re.search(orfc,seq[finc:]) return l_orf + map(antiparallele,l_orfc) Cours 2: formalisation de quelques problèmes biologiques : ressemblance entre les séquences Alignement de séquences : intérêt biologique : comparaison (étude de l'évolution), annotation des génomes, recherche de la fonction d'une protéine. Alignement optimal de 2 séquences: - qu'est ce qu'un alignement – impératifs "biologiques" – distance d'édition - complexité de l'algorithme "brute force" - programmation dynamique ("divide and conquer"): alignement global de 2 séquences (NWS), variantes, alignement local de 2 séquences (Smith et Waterman), complexité quadratique. - les différents systèmes de scores employés (basés sur l'aspect "biologique" du problème) : matrices de distances/similarité/substitutions (exemples : PAM, BLOSUM) (suite à voir en TD) Recherche sur banque – recherche de similarités locales : - nécessité d'une heuristique (problème de complexité) - algorithmes basiques (hashing table, FASTA, BLAST) TD 2 / TP 2 (2 * 2h): (fin du cours de recherche sur banque) Partie TP : Alignement : réalisation sous Scilab d'un programme d'alignement NWS (algorithme de programmation dynamique), si temps suffisant: modification en ses variantes (bestfit, Smith et Waterman)