4.6 Práctica 1: cadenas de Markov como Modelos de Secuencias

#pip install hidden_markov
# Import required Libraries
import numpy as np
from hidden_markov import hmm
import pandas as pd
import os
import matplotlib.pyplot as plt
### Also http://scikit-learn.sourceforge.net/stable/modules/hmm.html

Ejemplo 1: Conjunto de datos

Cargamos datos de secuencias de proteínas.

Carga el conjunto de datos prots-L30.txt que puedes descargar en Moodle. Como vamos a trabajar con cadenas de caracteres, convierte todas las columnas que involucren cadenas de caracteres al tipo character. Visualiza el conjunto de datos. La primera columna se refiere al identificador de la proteina en PDB. La segunda es la secuencia de aminoácidos, y la tercera es la estructura secundaria más probable predicha para esa secuencia en la base de datos. La cuarta columna es la longitud de la secuencia.

¿Tienen todas las secuencias la misma longitud?

dataFolder = './data/'
dataFile = 'prots-L30.txt'
dataFilepath = os.path.join(dataFolder,dataFile)
df = pd.read_csv(dataFilepath)
df.head()
pdb_id seq sst3 len
0 1AI0 FVNQHLCGSHLVEALYLVCGERGFFYTPKT CCCHHHHHHHHHHHHHHHHHHHCEEECCCC 30
1 1APH FVNQHLCGSHLVEALYLVCGERGFFYTPKA CCCCCCCCHHHHHHHHHHHHHHCEEECCCC 30
2 1B4G MISSVCVSSYRGRKSGNKPPSKTCLKEEMA CCCCCECCCCCCCCCCCCCCCCCCCCCCCC 30
3 1B9E FVNQHLCGEHLVEALYLVCGERGFFYTPKT CCCCCCCHHHHHHHHHHHHHHHCEEECCCC 30
4 1BH4 CGESCVWIPCISAALGCSCKNKVCYRNGIP CCCCCCCCCCCHHHHCCCCCCCCCCCCCCC 30
df.describe()
len
count 174.0
mean 30.0
std 0.0
min 30.0
25% 30.0
50% 30.0
75% 30.0
max 30.0
df.dtypes
pdb_id    object
seq       object
sst3      object
len        int64
dtype: object
df.seq[0]
'FVNQHLCGSHLVEALYLVCGERGFFYTPKT'
type(df.seq[0])
str

Ejemplo 2. Definiciones previas.

Define el alfabeto, formado por 20 aminoácidos, siguiendo este orden: RKDEQSCHNTWYMAILFVPG. Obtén las longitudes del alfabeto y la longitud de cada secuencia, así como el numero de instancias en el conjunto de datos.

alfabeto=[ele for ele in "RKDEQSCHNTWYMAILFVPG"]
print('Longitud del alfabeto ={}\nNúmero de secuencias ={}\nLongitud de las secuencias = {}'.format(len(alfabeto),
                               len(df['seq']),len(df['seq'][0])))
Longitud del alfabeto =20
Número de secuencias =174
Longitud de las secuencias = 30

Ejemplo 3. Vector de frecuencias en la primera posición

Vamos a calcular las probabilidades iniciales de cada aminoácido.

Calcula las frecuencias absolutas de cada aminoacido en la primera posición de la secuencia.

numSecuencias = len(df['seq'])
lenAlfab = len(alfabeto)
#frecAbsoluPos1 = [0 for i in range(lenAlfab)]
Pini = np.zeros(lenAlfab).astype(float)

for nseq in range(numSecuencias):
    secuenciaTabla = df.loc[nseq,'seq']
    primerAminoacido = secuenciaTabla[0]
    posicionAlfabeto = alfabeto.index(primerAminoacido)
    Pini[posicionAlfabeto] += 1

frecuenciasAbsolutasIniciales = dict(zip(alfabeto,Pini))
frecuenciasAbsolutasIniciales
{'R': 2.0,
 'K': 10.0,
 'D': 6.0,
 'E': 8.0,
 'Q': 3.0,
 'S': 8.0,
 'C': 9.0,
 'H': 3.0,
 'N': 3.0,
 'T': 3.0,
 'W': 0.0,
 'Y': 3.0,
 'M': 15.0,
 'A': 21.0,
 'I': 1.0,
 'L': 2.0,
 'F': 39.0,
 'V': 9.0,
 'P': 5.0,
 'G': 24.0}

Ejercicio 1. Vector inicial de probabilidades

Comprueba que la suma del vector calculado en el ejemplo anterior coincide con el número de instancias. Normaliza el vector dividiendo por la suma para transformarlo en un vector de probabilidades.

print('Suma de Pini: {}\nNúmero de secuencias: {}'.format(sum(Pini),numSecuencias))
sum(Pini),numSecuencias
# Frecuencias Relativas
sumFrecuenciasAbsolutas = sum(Pini)
Pini = Pini/sumFrecuenciasAbsolutas
print('\n')
print(Pini,Pini.sum())
frecuenciasRelativasIniciales = dict(zip(alfabeto,Pini))
print('\n')
print(frecuenciasRelativasIniciales)
Suma de Pini: 174.0
Número de secuencias: 174


[0.01149425 0.05747126 0.03448276 0.04597701 0.01724138 0.04597701
 0.05172414 0.01724138 0.01724138 0.01724138 0.         0.01724138
 0.0862069  0.12068966 0.00574713 0.01149425 0.22413793 0.05172414
 0.02873563 0.13793103] 1.0


{'R': 0.011494252873563218, 'K': 0.05747126436781609, 'D': 0.034482758620689655, 'E': 0.04597701149425287, 'Q': 0.017241379310344827, 'S': 0.04597701149425287, 'C': 0.05172413793103448, 'H': 0.017241379310344827, 'N': 0.017241379310344827, 'T': 0.017241379310344827, 'W': 0.0, 'Y': 0.017241379310344827, 'M': 0.08620689655172414, 'A': 0.1206896551724138, 'I': 0.005747126436781609, 'L': 0.011494252873563218, 'F': 0.22413793103448276, 'V': 0.05172413793103448, 'P': 0.028735632183908046, 'G': 0.13793103448275862}

Ejercicio 2. Matriz de Transiciones

Define una matriz de ceros, de tamaño \(20 \times 20\), de forma que los nombres de filas y columnas sean precisamente los nombres de cada aminoácido.

Actualiza esta matriz para que contenga las frecuencias absolutas de las \(20 \times 20\) posibles transiciones que hay entre los aminoácidos. Para ello tendrás que recorrer cada secuencia e identificar los dos residuos \(R_i \rightarrow R_f\) involucrados en las 29 transiciones posibles (tenemos secuencias de longitud 30) y actualizar el contador en la fila y columna correspondientes a la transición observada. Habrá que acumular los conteos recorriendo todas las secuencias del conjunto de datos.

columns = alfabeto
rows = alfabeto
MT = pd.DataFrame(0.0,columns=columns,index=rows) # inicializamos como float
for nseq in range(df.shape[0]):
    secuencia = df.loc[nseq,'seq']
    for naa in range(len(secuencia)-1): # recorremos hasta el penultimo
        pos1 = secuencia[naa]
        pos2 = secuencia[naa+1]
        MT.loc[pos1,pos2]+=1
MT
R K D E Q S C H N T W Y M A I L F V P G
R 32.0 14.0 6.0 10.0 9.0 6.0 12.0 5.0 7.0 9.0 3.0 17.0 2.0 18.0 24.0 29.0 5.0 4.0 15.0 52.0
K 17.0 27.0 7.0 21.0 10.0 20.0 17.0 10.0 12.0 49.0 3.0 6.0 1.0 18.0 9.0 13.0 2.0 11.0 23.0 12.0
D 4.0 9.0 15.0 6.0 4.0 16.0 12.0 4.0 5.0 5.0 2.0 5.0 1.0 7.0 7.0 17.0 3.0 9.0 12.0 13.0
E 71.0 29.0 16.0 16.0 5.0 11.0 7.0 3.0 8.0 7.0 2.0 8.0 1.0 52.0 14.0 15.0 4.0 9.0 4.0 13.0
Q 9.0 11.0 4.0 8.0 6.0 3.0 12.0 35.0 4.0 4.0 1.0 12.0 0.0 12.0 10.0 8.0 1.0 3.0 3.0 18.0
S 10.0 27.0 20.0 10.0 9.0 21.0 35.0 34.0 11.0 8.0 7.0 12.0 3.0 12.0 8.0 17.0 5.0 9.0 12.0 25.0
C 26.0 24.0 14.0 10.0 12.0 33.0 36.0 0.0 5.0 24.0 1.0 25.0 4.0 24.0 43.0 8.0 2.0 19.0 16.0 89.0
H 1.0 4.0 1.0 3.0 1.0 12.0 7.0 6.0 1.0 2.0 0.0 2.0 4.0 5.0 7.0 68.0 1.0 5.0 0.0 2.0
N 15.0 5.0 4.0 4.0 43.0 4.0 6.0 0.0 6.0 8.0 2.0 2.0 0.0 6.0 7.0 18.0 2.0 4.0 5.0 10.0
T 8.0 30.0 6.0 9.0 1.0 13.0 34.0 5.0 4.0 8.0 2.0 9.0 6.0 14.0 7.0 11.0 8.0 13.0 32.0 9.0
W 0.0 5.0 1.0 5.0 3.0 4.0 3.0 1.0 2.0 5.0 2.0 3.0 2.0 19.0 4.0 9.0 2.0 3.0 2.0 1.0
Y 8.0 4.0 2.0 1.0 21.0 6.0 40.0 3.0 9.0 35.0 1.0 4.0 0.0 8.0 11.0 49.0 3.0 5.0 3.0 24.0
M 3.0 4.0 7.0 4.0 1.0 3.0 6.0 0.0 1.0 2.0 4.0 0.0 0.0 6.0 7.0 7.0 2.0 3.0 4.0 2.0
A 14.0 6.0 14.0 24.0 14.0 16.0 45.0 5.0 5.0 12.0 5.0 10.0 12.0 37.0 13.0 56.0 28.0 12.0 14.0 37.0
I 7.0 14.0 7.0 8.0 4.0 16.0 8.0 4.0 10.0 9.0 1.0 20.0 0.0 38.0 15.0 16.0 8.0 7.0 29.0 17.0
L 10.0 22.0 8.0 24.0 12.0 16.0 44.0 8.0 6.0 11.0 21.0 43.0 5.0 21.0 13.0 36.0 21.0 86.0 9.0 10.0
F 8.0 3.0 2.0 7.0 0.0 10.0 16.0 2.0 1.0 9.0 2.0 34.0 0.0 7.0 7.0 10.0 36.0 48.0 6.0 6.0
V 9.0 9.0 4.0 46.0 4.0 7.0 55.0 1.0 40.0 11.0 8.0 6.0 2.0 20.0 14.0 11.0 6.0 10.0 10.0 17.0
P 10.0 28.0 10.0 5.0 2.0 21.0 12.0 3.0 8.0 19.0 5.0 9.0 2.0 30.0 3.0 12.0 4.0 16.0 48.0 38.0
G 30.0 19.0 7.0 72.0 4.0 56.0 19.0 2.0 11.0 29.0 6.0 10.0 6.0 13.0 18.0 21.0 36.0 11.0 43.0 18.0

Ejercicio 3. Matriz de transiciones

Normaliza la matriz calculada en el ejercicio anterior para que sea estocástica por filas.

print(MT.index)

for row in MT.index:
    fila = MT.loc[row,:]
    filaSum = fila.sum()
    MT.loc[row,:] = MT.loc[row,:]/filaSum

print(MT.loc['P',:].sum(),MT.loc[:,'P'].sum())

MT
Index(['R', 'K', 'D', 'E', 'Q', 'S', 'C', 'H', 'N', 'T', 'W', 'Y', 'M', 'A',
       'I', 'L', 'F', 'V', 'P', 'G'],
      dtype='object')
0.9999999999999999 1.1046864587116754
R K D E Q S C H N T W Y M A I L F V P G
R 0.114695 0.050179 0.021505 0.035842 0.032258 0.021505 0.043011 0.017921 0.025090 0.032258 0.010753 0.060932 0.007168 0.064516 0.086022 0.103943 0.017921 0.014337 0.053763 0.186380
K 0.059028 0.093750 0.024306 0.072917 0.034722 0.069444 0.059028 0.034722 0.041667 0.170139 0.010417 0.020833 0.003472 0.062500 0.031250 0.045139 0.006944 0.038194 0.079861 0.041667
D 0.025641 0.057692 0.096154 0.038462 0.025641 0.102564 0.076923 0.025641 0.032051 0.032051 0.012821 0.032051 0.006410 0.044872 0.044872 0.108974 0.019231 0.057692 0.076923 0.083333
E 0.240678 0.098305 0.054237 0.054237 0.016949 0.037288 0.023729 0.010169 0.027119 0.023729 0.006780 0.027119 0.003390 0.176271 0.047458 0.050847 0.013559 0.030508 0.013559 0.044068
Q 0.054878 0.067073 0.024390 0.048780 0.036585 0.018293 0.073171 0.213415 0.024390 0.024390 0.006098 0.073171 0.000000 0.073171 0.060976 0.048780 0.006098 0.018293 0.018293 0.109756
S 0.033898 0.091525 0.067797 0.033898 0.030508 0.071186 0.118644 0.115254 0.037288 0.027119 0.023729 0.040678 0.010169 0.040678 0.027119 0.057627 0.016949 0.030508 0.040678 0.084746
C 0.062651 0.057831 0.033735 0.024096 0.028916 0.079518 0.086747 0.000000 0.012048 0.057831 0.002410 0.060241 0.009639 0.057831 0.103614 0.019277 0.004819 0.045783 0.038554 0.214458
H 0.007576 0.030303 0.007576 0.022727 0.007576 0.090909 0.053030 0.045455 0.007576 0.015152 0.000000 0.015152 0.030303 0.037879 0.053030 0.515152 0.007576 0.037879 0.000000 0.015152
N 0.099338 0.033113 0.026490 0.026490 0.284768 0.026490 0.039735 0.000000 0.039735 0.052980 0.013245 0.013245 0.000000 0.039735 0.046358 0.119205 0.013245 0.026490 0.033113 0.066225
T 0.034934 0.131004 0.026201 0.039301 0.004367 0.056769 0.148472 0.021834 0.017467 0.034934 0.008734 0.039301 0.026201 0.061135 0.030568 0.048035 0.034934 0.056769 0.139738 0.039301
W 0.000000 0.065789 0.013158 0.065789 0.039474 0.052632 0.039474 0.013158 0.026316 0.065789 0.026316 0.039474 0.026316 0.250000 0.052632 0.118421 0.026316 0.039474 0.026316 0.013158
Y 0.033755 0.016878 0.008439 0.004219 0.088608 0.025316 0.168776 0.012658 0.037975 0.147679 0.004219 0.016878 0.000000 0.033755 0.046414 0.206751 0.012658 0.021097 0.012658 0.101266
M 0.045455 0.060606 0.106061 0.060606 0.015152 0.045455 0.090909 0.000000 0.015152 0.030303 0.060606 0.000000 0.000000 0.090909 0.106061 0.106061 0.030303 0.045455 0.060606 0.030303
A 0.036939 0.015831 0.036939 0.063325 0.036939 0.042216 0.118734 0.013193 0.013193 0.031662 0.013193 0.026385 0.031662 0.097625 0.034301 0.147757 0.073879 0.031662 0.036939 0.097625
I 0.029412 0.058824 0.029412 0.033613 0.016807 0.067227 0.033613 0.016807 0.042017 0.037815 0.004202 0.084034 0.000000 0.159664 0.063025 0.067227 0.033613 0.029412 0.121849 0.071429
L 0.023474 0.051643 0.018779 0.056338 0.028169 0.037559 0.103286 0.018779 0.014085 0.025822 0.049296 0.100939 0.011737 0.049296 0.030516 0.084507 0.049296 0.201878 0.021127 0.023474
F 0.037383 0.014019 0.009346 0.032710 0.000000 0.046729 0.074766 0.009346 0.004673 0.042056 0.009346 0.158879 0.000000 0.032710 0.032710 0.046729 0.168224 0.224299 0.028037 0.028037
V 0.031034 0.031034 0.013793 0.158621 0.013793 0.024138 0.189655 0.003448 0.137931 0.037931 0.027586 0.020690 0.006897 0.068966 0.048276 0.037931 0.020690 0.034483 0.034483 0.058621
P 0.035088 0.098246 0.035088 0.017544 0.007018 0.073684 0.042105 0.010526 0.028070 0.066667 0.017544 0.031579 0.007018 0.105263 0.010526 0.042105 0.014035 0.056140 0.168421 0.133333
G 0.069606 0.044084 0.016241 0.167053 0.009281 0.129930 0.044084 0.004640 0.025522 0.067285 0.013921 0.023202 0.013921 0.030162 0.041763 0.048724 0.083527 0.025522 0.099768 0.041763

Extra: mapa de calor de la matriz

Realizar un mapa de calor de la matriz de transiciones con el paquete seaborn

import seaborn as sns
sns.heatmap(MT)
<AxesSubplot:>
_images/04.06_CadenasMarkov_22_1.png

Extra: es una matriz regular?

Comprobar que la matriz de transiciones es una matriz regular.

MTdata = MT.to_numpy()
MTdataTranspose= MTdata.transpose()

numzeros0 = MTdataTranspose.shape[0]*MTdataTranspose.shape[1]-np.count_nonzero(MTdataTranspose)
matrix = np.matmul(MTdataTranspose,MTdataTranspose)
numzeros1 =MTdataTranspose.shape[0]*MTdataTranspose.shape[1]-np.count_nonzero(matrix)
numzeros0,numzeros1
(14, 0)

Ejemplo 4. Distribución de Equilibrio

Supón que hemos llamado MT a la matriz de transiciones hallada en el ejercicio anterior.

Utilizando la función eig del módulo linalg de numpy, que calcula autovalores y autovectores de una matriz cuadrada, obten las probabilidades de equilibrio asociadas a cada aminoácido según el modelo. La función eig devuelve una lista de dos elementos:

  • eigenValues contiene los autovectores,

  • eigenVectors es una matriz cuyas columnas son los autovectores asociados a cada autovalor (siguiendo el orden dado en values).

Autovalores y autovectores

# https://numpy.org/doc/stable/reference/generated/numpy.linalg.eig.html

eigVal,eigVec = np.linalg.eig(MTdataTranspose)
eigVal[0]
(1+0j)
eigVec[:,0]
array([0.2382502 +0.j, 0.24467417+0.j, 0.12601374+0.j, 0.23640415+0.j,
       0.13599602+0.j, 0.23976837+0.j, 0.34758931+0.j, 0.10802277+0.j,
       0.12708041+0.j, 0.21794427+0.j, 0.06293577+0.j, 0.19054646+0.j,
       0.04222282+0.j, 0.30020173+0.j, 0.1964877 +0.j, 0.35043236+0.j,
       0.1397589 +0.j, 0.22869757+0.j, 0.24098499+0.j, 0.34057742+0.j])
eigVec[:,0].dtype
dtype('complex128')
autovector = eigVec[:,0]
autovectorReal = np.real(autovector)
autovectorReal
array([0.2382502 , 0.24467417, 0.12601374, 0.23640415, 0.13599602,
       0.23976837, 0.34758931, 0.10802277, 0.12708041, 0.21794427,
       0.06293577, 0.19054646, 0.04222282, 0.30020173, 0.1964877 ,
       0.35043236, 0.1397589 , 0.22869757, 0.24098499, 0.34057742])
sum(autovectorReal)
4.114589128455469
# hacemos que pertenezca al simplex
autovectorRealNorm = autovectorReal/sum(autovectorReal)
autovectorRealNorm
array([0.05790376, 0.05946503, 0.03062608, 0.05745511, 0.03305215,
       0.05827274, 0.08447728, 0.0262536 , 0.03088532, 0.05296866,
       0.01529576, 0.04630996, 0.01026173, 0.07296032, 0.0477539 ,
       0.08516825, 0.03396667, 0.05558212, 0.05856842, 0.08277313])

Ejercicio 4. Preguntas.

Observa el código del ejercicio anterior y responde a las siguientes preguntas.

  1. En la teorı́a hemos visto que la distribución de equilibrio q es la solución del sistema lineal \(\mathbf{q} = \mathbf{q}P\) , siendo \(P\) la matriz de transiciones. ¿Por qué calculamos entonces autovalores y autovectores para hallar q?

  2. ¿Por qué utilizamos la matriz transpuesta en lugar de \(MT\) directamente?

  3. ¿Por qué utilizamos la primera columna de la matriz de autovectores y no otra?

  4. ¿Qué hace la función np.real que aparece en el código? ¿Por qué es necesaria?

Ejemplo 5. Representación gráfica.

Representa gráficamente la distribución anterior mediante un diagrama de barras. Ordena las probabilidades de mayor a menor.

index = np.argsort(autovectorRealNorm,)
indexDecreasing = index[::-1] # decreasing order
indexDecreasing
array([15,  6, 19, 13,  1, 18,  5,  0,  3, 17,  9, 14, 11, 16,  4,  8,  2,
        7, 10, 12])
len(alfabeto),len(indexDecreasing)
(20, 20)
alfabetoNP = np.asarray(alfabeto)
alfabetoNP
array(['R', 'K', 'D', 'E', 'Q', 'S', 'C', 'H', 'N', 'T', 'W', 'Y', 'M',
       'A', 'I', 'L', 'F', 'V', 'P', 'G'], dtype='<U1')
# ordenar las frecuencias del vector de estado estable
vectorEstable = autovectorRealNorm[indexDecreasing]
labels = alfabetoNP[indexDecreasing]
plt.bar(np.arange(len(vectorEstable)),vectorEstable)
plt.xticks(np.arange(len(vectorEstable)),labels)
plt.show()
_images/04.06_CadenasMarkov_40_0.png

Ejercicio 5. Distribución empírica.

Calcula, contando frecuencias en el conjunto de datos, la distribucion de frecuencias relativas de los aminoácidos. Representa dos diagramas de barras superpuestos con esta distribucion y la obtenida en el Ejemplo anterior. ¿Son comparables?

alfabeto


Pempirica = np.zeros(lenAlfab).astype(float)
Pempirica

for nseq in range(df.shape[0]):
    secuencia = df.loc[nseq,'seq']
    for naa in range(len(secuencia)): # recorremos hasta el ultimo
        AA = secuencia[naa]
        # qué AA es?
        indexAA = alfabeto.index(AA)
        Pempirica[indexAA] += 1
print(Pempirica)

PempiricaFrecuencias = Pempirica / sum(Pempirica)
print(PempiricaFrecuencias)
[294. 304. 161. 301. 168. 302. 435. 134. 159. 269.  78. 240.  66. 388.
 242. 433. 218. 296. 295. 437.]
[0.05632184 0.05823755 0.03084291 0.05766284 0.03218391 0.05785441
 0.08333333 0.0256705  0.03045977 0.05153257 0.01494253 0.04597701
 0.01264368 0.0743295  0.04636015 0.08295019 0.04176245 0.05670498
 0.05651341 0.08371648]
print(np.abs(autovectorRealNorm - PempiricaFrecuencias))

print((autovectorRealNorm - PempiricaFrecuencias).max())
[0.00158192 0.00122748 0.00021683 0.00020773 0.00086824 0.00041833
 0.00114395 0.0005831  0.00042555 0.00143609 0.00035323 0.00033295
 0.00238194 0.00136918 0.00139375 0.00221806 0.00779578 0.00112287
 0.00205501 0.00094335]
0.002218058754909241
plt.bar(np.arange(len(vectorEstable)),vectorEstable,alpha=0.5,label='estable')
plt.bar(np.arange(len(vectorEstable)),PempiricaFrecuencias[indexDecreasing],alpha=0.5,label='empírica')
plt.xticks(np.arange(len(vectorEstable)),labels)
plt.legend()
plt.show()
_images/04.06_CadenasMarkov_44_0.png

Ejercicio 6. Verosimilitudes de secuencias

Escribe una función, llamada myloglik, que calcule la log-verosimilitud de una secuencia según el modelo de Markov. Los argumentos de entrada han de ser:

  1. el vector de probabilidad inicial vecProbInicial

  2. la matriz de transiciones MT

  3. el alfabeto de 20 aminoácidos definido en el ejemplo 1 alfabeto

  4. la secuencia (como lista de aminoácidos) de la que queremos calcular la verosimilitud secuencia

Tanto el vector de probabilidad inicial como la matriz de transiciones han de tener la misma ordenación que el alfabeto dado.

Compara las verosimilitudes de las siguientes secuencias:

  • SEQWENCIAVERQSMILYES

  • FVCQHLVCQHLVCQHLVCQQ.

def myloglik(vecProbInicial, matrizTransicion, alfa, secuencia):
    
    loglik = 0.0
    
    primeraLetra = secuencia[0]
    primeraPosicionEnAlfabeto = alfa.index(primeraLetra)
    
    loglik += np.log(vecProbInicial[primeraPosicionEnAlfabeto])
    
    for i in range(len(secuencia)-1):
        
        letraEntrada = secuencia[i]
        letraSalida = secuencia[i+1]
        
        posicionLetraEntradaAlfabeto = alfa.index(letraEntrada)
        posicionLetraSalidaAlfabeto = alfa.index(letraSalida)
        probabilidadTransicion = matrizTransicion.iloc[posicionLetraEntradaAlfabeto,
                                                 posicionLetraSalidaAlfabeto]
        
        loglik += np.log(probabilidadTransicion)
    return loglik
secuencia1 = "SEQWENCIAVERQSMILYES"
loglik1 = myloglik(Pini, MT, alfabeto, secuencia1)
lik1=np.exp(loglik1)
print(secuencia1,'\nLoglikelihood: {}\nLikelihood:: {}\n'.format(loglik1,lik1))

secuencia2 = "FVCQHLVCQHLVCQHLVCQQ"
loglik2 = myloglik(Pini, MT, alfabeto, secuencia2)
lik2=np.exp(loglik2)
print(secuencia2,'\nLoglikelihood: {}\nLikelihood:: {}\n'.format(loglik2,lik2))
SEQWENCIAVERQSMILYES 
Loglikelihood: -64.0330953932442
Likelihood:: 1.5516008595950296e-28

FVCQHLVCQHLVCQHLVCQQ 
Loglikelihood: -38.54576794984071
Likelihood:: 1.8188030702995e-17