In [91]:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import statistics
import random
import math
import gdown

from itertools import *

Задача 1¶

Задача 1.1¶

In [2]:
random.seed(10)

#Генерируем два набора чисел размером n1 n2 из нормальных распределений с заданными параметрами
n1=1000
n2=500

set1 = np.random.normal(0, 1, n1)
set2 = np.random.normal(1, 1, n2)

#Смешиваем их в один набор, сразу сортируем его
data = np.sort(np.concatenate((set1, set2)))

sns.histplot(set1, color='orange', fill=True, label="N(0,1)")
sns.histplot(set2, color='violet', fill=True, label="N(1,1)")

plt.legend()
plt.show()

Задача 1.2¶

In [3]:
#Задаем функции для Е- и М-шага
def e_step(data, border):
  mu1 = np.mean(data[:border])
  sigma1 = np.std(data[:border])
  mu2 = np.mean(data[border:])
  sigma2 = np.std(data[border:])

  return mu1, sigma1, mu2, sigma2

def m_step(data, mu1, mu2, sigma1, sigma2):
  max_likelihood = -1000
  sum1 = 0
  sum2 = 0
  for m in range(len(data)):
    sum1 = 0
    sum2 = 0
    current_likelihood = 0
    for i in range(m):
      sum1 += (data[i]-mu1)**2/(2*sigma1)**2
    for j in range(m+1, len(data)):
      sum2 += (data[j]-mu2)**2/(2*sigma2)**2
    current_likelihood = -sum1-sum2
    if current_likelihood > max_likelihood:
      max_likelihood = current_likelihood
      border = m
  return border
In [8]:
def density(mu, sigma, x):
  dens = math.e**(-(x-mu)**2/(2*sigma**2)) / (sigma*(2*math.pi)**0.5)
  return dens

#соберем шаги в ЕМ-алгоритм, в явном виде вычислим вероятности отнести число к 1 или 2 распределению
def EM_algorithm(data):
  list_mu1 = []
  list_mu2 = []
  size_set1 = []
  size_set2 = []
  border = len(data)//2

  for k in range(1,21):
    mu1, sigma1, mu2, sigma2 = e_step(data, border)
    border = m_step(data, mu1, mu2, sigma1, sigma2)

  probabilities=[]
  for number in data:
    prob_number=[]
    prob1 = (border*density(mu1, sigma1, number))/(border*density(mu1, sigma1, number) + (len(data)-border)*density(mu2, sigma2, number))
    #prob 2 можно было бы вычислить 1-prob1, но тот факт, что эти два числа сложатся в единицу будет гарантией, что я не ошиблась в формуле
    prob2 = ((len(data)-border)*density(mu2, sigma2, number))/(border*density(mu1, sigma1, number) + (len(data)-border)*density(mu2, sigma2, number))
    prob_number.append(prob1)
    prob_number.append(prob2)
    probabilities.append(prob_number)

  return (border, mu1, mu2, probabilities)
In [ ]:
#добавим визуализацию каждые пять шагов, чтобы "следить за прогрессом"
def EM_algorithm_visual(data):
  list_mu1 = []
  list_mu2 = []
  size_set1 = []
  size_set2 = []
  border = len(data)//2

  for k in range(1,21):
    mu1, sigma1, mu2, sigma2 = e_step(data, border)
    border = m_step(data, mu1, mu2, sigma1, sigma2)

    list_mu1.append(mu1)
    list_mu2.append(mu2)
    size_set1.append(border)

    if k==1 or k%5==0:
      print("ITERATION", k)
      print( "mu1", mu1)
      print( "mu2", mu2)
      print( "sigma1", sigma1)
      print( "sigma2", sigma2)
      print( "size of set1", border)
      print( "size of set2", len(data)-border)
      supposed_set1 = data[:border]
      supposed_set2 = data[border:]
      sns.histplot(set1, color='violet', fill=True, label='true set 1')
      sns.histplot(supposed_set1, color='blue', fill=True, label='predicted set 1')
      plt.legend()
      plt.show()
      sns.histplot(set2, color='orange', fill=True, label='true set 2')
      sns.histplot(supposed_set2, color='red', fill=True, label='predicted set 2')
      plt.legend()
      plt.show()

  plt.plot(list_mu1, label='mu1')
  plt.xlabel("Iterations")
  plt.legend()
  plt.show()
  plt.plot(list_mu2, label='mu2')
  plt.xlabel("Iterations")
  plt.legend()
  plt.show()
  plt.plot(size_set1, label='size of set1')
  plt.xlabel("Iterations")
  plt.legend()
  plt.show()

  return (border, mu1, mu2, sigma1, sigma2)

EM_algorithm_visual(data)
ITERATION 1
mu1 -0.5446096914284532
mu2 1.1614921889368086
sigma1 0.6134187648088477
sigma2 0.6841361482367456
size of set1 745
size of set2 755
ITERATION 5
mu1 -0.5776942822258133
mu2 1.126412508120323
sigma1 0.6038146278666493
sigma2 0.6934039853078701
size of set1 708
size of set2 792
ITERATION 10
mu1 -0.6234521947825068
mu2 1.0812309336382575
sigma1 0.5901912605873494
sigma2 0.7051116019114307
size of set1 679
size of set2 821
ITERATION 15
mu1 -0.6326491388001118
mu2 1.0722247516967893
sigma1 0.5876076525623156
sigma2 0.7075963925550735
size of set1 671
size of set2 829
ITERATION 20
mu1 -0.6349570522545914
mu2 1.0699796363154732
sigma1 0.586961402949591
sigma2 0.7082181907851283
size of set1 670
size of set2 830

Для одномерного случая ЕМ-алгоритм может только подобрать оптимальную границу, числа до которой он назовет набором 1, а после которой - набором 2, это хорошо видно на гистограммах. В случае с нормальными распределениями с заданными параметрами ( N(0,1) и N(1,1) ), мне кажется, перекрывание хвостов слишком велико, чтобы алгоритм работал корректно.

Упражнение для раных размеров выборок¶

In [5]:
def generate_data(n1, n2):
  N = n1 + n2
  set1 = np.random.normal(0, 1, n1)
  set2 = np.random.normal(1, 1, n2)

  data = np.sort(np.concatenate((set1, set2)))

  return data
In [19]:
data1=generate_data(10,5)

size1, mu1, mu2, probabilities = EM_algorithm(data1)
print("ЕМ алгоритм предсказал:")
print("Размер выборки 1 - ", size1)
print("Размер выборки 2 - ", len(data1)-size1)
print("Мат ожидание mu1 - ", mu1)
print("Мат ожидание mu2 - ", mu2)
print("Вероятности каждого числа прийти из распределения 1 и распределения 2 -", probabilities)
print("--------")
print("Правильные ответы:")
print("Размер выборки 1 - 10")
print("Размер выборки 2 - 5")
print("Мат ожидание mu1 - 0")
print("Мат ожидание mu2 - 1")
ЕМ алгоритм предсказал:
Размер выборки 1 -  6
Размер выборки 2 -  9
Мат ожидание mu1 -  -0.6829857214402241
Мат ожидание mu2 -  1.0014445989374807
Вероятности каждого числа прийти из распределения 1 и распределения 2 - [[0.9999921428571301, 7.857142869908976e-06], [0.9999836512015062, 1.6348798493701047e-05], [0.9956000788845433, 0.004399921115456775], [0.7418664074921703, 0.2581335925078298], [0.7342243629976319, 0.26577563700236806], [0.4468239305866354, 0.5531760694133646], [0.3267454258266011, 0.6732545741733988], [0.1407233476274981, 0.859276652372502], [0.13716351333451324, 0.8628364866654867], [0.07951492538534938, 0.9204850746146506], [0.061929154718052035, 0.9380708452819481], [0.037366132966073086, 0.962633867033927], [0.013961615429088208, 0.9860383845709118], [0.0067091176907595395, 0.9932908823092403], [0.005846620332958259, 0.9941533796670418]]
--------
Правильные ответы:
Размер выборки 1 - 10
Размер выборки 2 - 5
Мат ожидание mu1 - 0
Мат ожидание mu2 - 1
In [160]:
data2=generate_data(100,50)

size1, mu1, mu2, probabilities = EM_algorithm(data2)
print("ЕМ алгоритм предсказал:")
print("Размер выборки 1 - ", size1)
print("Размер выборки 2 - ", len(data2)-size1)
print("Мат ожидание mu1 - ", mu1)
print("Мат ожидание mu2 - ", mu2)
#на html страничке эти вероятности занимают очень много места - выведу только первые десять для нагляности
print("Вероятности каждого числа прийти из распределения 1 и распределения 2 -", probabilities[:10])
print("--------")
print("Правильные ответы:")
print("Размер выборки 1 - 100")
print("Размер выборки 2 - 50")
print("Мат ожидание mu1 - 0")
print("Мат ожидание mu2 - 1")
ЕМ алгоритм предсказал:
Размер выборки 1 -  59
Размер выборки 2 -  91
Мат ожидание mu1 -  -0.8762737659851891
Мат ожидание mu2 -  1.100233376643748
Вероятности каждого числа прийти из распределения 1 и распределения 2 - [[0.9986954239297332, 0.0013045760702667792], [0.9982283807271941, 0.0017716192728059288], [0.9977429574948607, 0.002257042505139206], [0.9973009269498366, 0.0026990730501634487], [0.9972936448126304, 0.0027063551873695974], [0.9971186994635394, 0.0028813005364605637], [0.9961998714200562, 0.003800128579943771], [0.9958954153431863, 0.004104584656813744], [0.9950755783272539, 0.00492442167274607], [0.9939922918117275, 0.0060077081882724155]]
--------
Правильные ответы:
Размер выборки 1 - 100
Размер выборки 2 - 50
Мат ожидание mu1 - 0
Мат ожидание mu2 - 1
In [159]:
data3=generate_data(1000,500)

size1, mu1, mu2, probabilities = EM_algorithm(data3)
print("ЕМ алгоритм предсказал:")
print("Размер выборки 1 - ", size1)
print("Размер выборки 2 - ", len(data3)-size1)
print("Мат ожидание mu1 - ", mu1)
print("Мат ожидание mu2 - ", mu2)
#на html страничке эти вероятности занимают очень много места - выведу только первые десять для нагляности
print("Вероятности каждого числа прийти из распределения 1 и распределения 2 -", probabilities[:10])
print("--------")
print("Правильные ответы:")
print("Размер выборки 1 - 1000")
print("Размер выборки 2 - 500")
print("Мат ожидание mu1 - 0")
print("Мат ожидание mu2 - 1")
ЕМ алгоритм предсказал:
Размер выборки 1 -  734
Размер выборки 2 -  766
Мат ожидание mu1 -  -0.5710396451858859
Мат ожидание mu2 -  1.234044588284195
Вероятности каждого числа прийти из распределения 1 и распределения 2 - [[0.9999945232521766, 5.47674782342883e-06], [0.9999851435687469, 1.4856431253075374e-05], [0.999982411689097, 1.758831090291378e-05], [0.9999792692835755, 2.0730716424456953e-05], [0.9999576531124774, 4.234688752252021e-05], [0.999940462615171, 5.95373848289209e-05], [0.9999345308555373, 6.546914446272247e-05], [0.9999226197704194, 7.738022958061423e-05], [0.9999153004441598, 8.469955584018715e-05], [0.999892850823654, 0.00010714917634596944]]
--------
Правильные ответы:
Размер выборки 1 - 1000
Размер выборки 2 - 500
Мат ожидание mu1 - 0
Мат ожидание mu2 - 1

Три упражнения продемонстрировали, что проблема была не в малом размере выборки (с увеличением количества элементов качество не улучшилось), а все же в перекрывании данных - средние лежат на расстоянии в стандартное отклонение, из-за чего нельзя четко разграничить их одной прямой

Другой пример¶

(Пример, показывающий, что алгоритм все-таки работает)

На наборах данных, у которых средние отличаются больше, ЕМ-алгоритм работает корректнее.

In [ ]:
n1 = 1000
n2 = 500
N = n1 + n2

random.seed(10)
set1 = np.random.normal(0, 1, n1)
set2 = np.random.normal(5, 1, n2)

data_test = np.sort(np.concatenate((set1, set2)))

sns.histplot(set1, color='orange', fill=True, label="N(0,1)")
sns.histplot(set2, color='violet', fill=True, label="N(5,1)")
plt.legend()
plt.show()
In [ ]:
EM_algorithm_visual(data_test)
ITERATION 1
mu1 -0.3819378123653121
mu2 3.773742028443601
sigma1 0.7301003842571164
sigma2 1.973739541634068
size of set1 779
size of set2 721
ITERATION 5
mu1 -0.20717026444257006
mu2 4.338384765370443
sigma1 0.8053136889456561
sigma2 1.6399068708665174
size of set1 912
size of set2 588
ITERATION 10
mu1 -0.03139007787213524
mu2 4.894348094878663
sigma1 0.9236995761806746
sigma2 1.1366982074305512
size of set1 980
size of set2 520
ITERATION 15
mu1 -0.004637704382946664
mu2 4.958027117860511
sigma1 0.949204162362557
sigma2 1.0697594037542155
size of set1 986
size of set2 514
ITERATION 20
mu1 -0.004637704382946664
mu2 4.958027117860511
sigma1 0.949204162362557
sigma2 1.0697594037542155
size of set1 986
size of set2 514
Out[ ]:
(986,
 -0.004637704382946664,
 4.958027117860511,
 0.949204162362557,
 1.0697594037542155)

Задание 2¶

Задача 2.1¶

In [35]:
#Задаем исходные параметры модели
alphabet = 'ab'

real_init_prob = {'a' : 0.5,
                  'b' : 0.5}
real_prob = {"aa" : 0.6,
             "ab" : 0.4,
             "ba" : 0.3,
             "bb" : 0.7}

# Функция для генерации последовательности
def generate_sequence(length):
    sequence=""
    letter = 'a' if random.random() < real_init_prob['a'] else 'b'
    for _ in range(length):
        sequence+=letter
        prev_letter=letter
        if prev_letter == 'a':
            letter = 'a' if random.random() < real_prob['aa'] else 'b'
        else:
            letter = 'a' if random.random() < real_prob['ba'] else 'b'
    return sequence

#сразу зададим все функции, которые нужны будут, чтобы оценить параметры марковской модели любого порядка, а не только первого

#функция подсчета количества к-меров до определенной позиции
def count_kmers(k, alphabet, sequences, end):
  #создаем словарь со всеми возможными к-мерами заданной длиным из букв нашего алфавита
  kmers=[]
  for i in product(alphabet, repeat=k):
    kmer = "".join(i)
    kmers.append(kmer)
  kmers_dict = dict.fromkeys(kmers, 0)
  #считаем количество каждого к-мера
  for seq in sequences:
    for kmer in kmers:
      counter=0
      for i in range(end-k+1):
        if seq[i:i+k]==kmer:
          counter+=1
      kmers_dict[kmer] += counter
  return kmers_dict

#функция подсчета частоты к-меров до определенной позиции
def kmers_freq(k, sequences, end):
  kmers_dict = count_kmers(k, alphabet, sequences, end)
  prefix_dict = count_kmers(k-1, alphabet, sequences, end-1)

  kmer_freq_dict = dict.fromkeys(kmers_dict.keys(), 0)
  for kmer in kmers_dict.keys():
    prefix = kmer[:-1]
    kmer_freq_dict[kmer] = "{:.3f}".format(kmers_dict[kmer] / prefix_dict[prefix])
  return kmer_freq_dict

#функция оценки параметров бернуллиевской модели
def estimate_bernoulli_model(sequences, alphabet, end):
  freq_dict = dict.fromkeys(list(alphabet), 0)
  for seq in sequences:
    for letter in freq_dict.keys():
       freq_dict[letter] += seq.count(letter, 0, end)
  for letter in freq_dict.keys():
    freq_dict[letter] = freq_dict[letter]/(len(sequences)*end)
  return freq_dict

#функция оценки параметров марковской модели любого порядка
def estimate_markov_model(order, sequences):
  #считаем распределения вероятностей для первых order-1 символов
  probs = [estimate_bernoulli_model(sequences, alphabet, 1)]
  for i in range(2, order+1):
    probs.append( kmers_freq(i, sequences, i+1) )

  kmers_freq_dict1 = estimate_bernoulli_model(sequences, alphabet, 1)
  #распределения вероятностей для остальных символов
  probs.append( kmers_freq(order+1, sequences, len(sequences[0])) )
  return probs

# Генерируем 1000 последовательностей длиной 3000 нуклеотидов
sequences = [generate_sequence(3000) for _ in range(1000)]

estimate_markov_model(1, sequences)
Out[35]:
[{'a': 0.497, 'b': 0.503},
 {'aa': '0.599', 'ab': '0.401', 'ba': '0.300', 'bb': '0.700'}]

Параметры хорошо соотносятся с теми, что я задала выше:

{'a' : 0.5, 'b' : 0.5}

{"aa" : 0.6, "ab" : 0.4, "ba" : 0.3, "bb" : 0.7}

Задача 2.2¶

Задаем необходимые функции

In [133]:
def ln_likelihood_Markov(probabilities, order, sequences):
  L=0
  for seq in sequences:
    #print(seq)
    L+=math.log(len(seq), math.e)
    for i in range(order):
      #print(seq[0:i+1])
      L+=math.log(float(probabilities[i][seq[0:i+1]]), math.e)
    #print("-------")
    for i in range(order, len(seq)):
      L+=math.log(float(probabilities[order][seq[i-order:i]+seq[i]]), math.e)
  return L

def ln_likelihood_bernoulli(probabilities, sequences):
  L = 0
  for seq in sequences:
    L+=math.log(len(seq), math.e)
    for letter in seq:
        L+=math.log(probabilities[letter], math.e)
  return L

def indep_params(alphabet, order):
  return (len(alphabet)**(order+1))-1

def BIC(n, k, lnL):
  #k - число параметров модели
  #n - размер обучающей выборки
  #lnL - ln(likelihood)
  return k * math.log(n, math.e) - 2*lnL

def AIC(k, lnL):
  #n - размер обучающей выборки
  #lnL - ln(likelihood)
  return 2*k - 2*lnL

#ln_likelihood_Markov(kmers_freq_dict, 3, test_seq)

Оцениваем параметры для бернуллиевской модели и марковский моделей 1-3 порядков. Из построения мы знаем, что все последовательности строились одинаково, поэтому перемешивать их для разделения на тестовую и тренировочную выборки необязательно.

In [131]:
train_set = sequences[:800]
test_set = sequences[800:]

alphabet = 'ab'

Бернуллиевская модель¶

In [134]:
params = estimate_bernoulli_model(train_set, alphabet, len(train_set[0]))
k = indep_params(alphabet, 0)
lnL = ln_likelihood_bernoulli(params, test_set)

bic = BIC(len(train_set), k, lnL)
aic = AIC(k, lnL)

print("AIC", aic)
print("BIC", bic)
AIC 816418.6689926077
BIC 816423.3536043355

Марковская модель 1-го порядка¶

In [135]:
params = estimate_markov_model(order=1, sequences=train_set)
k = indep_params(alphabet, 1)
lnL =  ln_likelihood_Markov(params, order=1, sequences=test_set)

bic = BIC(len(train_set), k, lnL)
aic = AIC(k, lnL)

print("AIC", aic)
print("BIC", bic)
AIC 761385.1288494183
BIC 761399.1826846013

Марковская модель 2-го порядка¶

In [136]:
params = estimate_markov_model(order=2, sequences=train_set)
k = indep_params(alphabet, order=2)
lnL =  ln_likelihood_Markov(params, order=2, sequences=test_set)

bic = BIC(len(train_set), k, lnL)
aic = AIC(k, lnL)

print("AIC", aic)
print("BIC", bic)
AIC 761392.584674897
BIC 761425.3769569907

Марковская модель 3-го порядка¶

In [129]:
params = estimate_markov_model(order=3, sequences=train_set)
k = indep_params(alphabet, order=3)
lnL = ln_likelihood_Markov(params, order=3, sequences=test_set)

bic = BIC(len(train_set), k, lnL)
aic = AIC(k, lnL)

print("AIC", aic)
print("BIC", bic)
AIC 761410.1336455714
BIC 761480.4028214865

AIC

Бернуллиевская модель: 816418.6689926077

Марковская модель 1-го порядка: 761385.1288494183 (Победитель!)

Марковская модель 2-го порядка: 761392.584674897

Марковская модель 3-го порядка: 761410.1336455714

BIC

Бернуллиевская модель: 816423.3536043355

Марковская модель 1-го порядка: 761399.1826846013 (Победитель!)

Марковская модель 2-го порядка: 761425.3769569907

Марковская модель 3-го порядка: 761480.4028214865

Действительно, баланса между правдоподобием и количеством параметров достигла марковская модель 1-го порядка, которая и была использована для генерации последовательностей :)

Задача 2.3¶

In [151]:
my_input = open('genome_bacillus.fna')
lines = my_input.readlines()
genome_seq=""
for line in lines:
  if line[0]!=">":
    line=line.replace("\n", "")
    genome_seq+=line

print(len(genome_seq))

genome_pieces=[]
for i in range(len(genome_seq)//1000):
  genome_pieces.append(genome_seq[i*1000:(i+1)*1000])

print(len(genome_pieces))
4215606
4215

В случае с геномом уже стоит перемешать полученные последовательности

In [148]:
random.shuffle(genome_pieces)

train_pieces = genome_pieces[:3000] #будем обучать на 4000 последовательностях, а тестировать на остальных
test_pieces = genome_pieces[3000:]

alphabet = "ATGC"

Бернуллиевская модель¶

In [149]:
params = estimate_bernoulli_model(train_pieces, alphabet, len(train_pieces[0]))
k = indep_params(alphabet, 0)
lnL = ln_likelihood_bernoulli(params, test_pieces)

bic = BIC(len(train_pieces), k, lnL)
aic = AIC(k, lnL)

print("AIC", aic)
print("BIC", bic)
{'A': 0.281867, 'T': 0.28293033333333334, 'G': 0.21687633333333334, 'C': 0.21832633333333334}
AIC 3331344.947942344
BIC 3331362.967045047

Марковские модели 1-5 порядков¶

In [158]:
for i in range(1, 6):
  print("Марковская модель", i, '-го порядка')
  params = estimate_markov_model(order=i, sequences=train_pieces)
  k = indep_params(alphabet, order=i)
  lnL = ln_likelihood_Markov(params, order=i, sequences=test_pieces)

  bic = BIC(len(train_pieces), k, lnL)
  aic = AIC(k, lnL)

  print("AIC", aic)
  print("BIC", bic)
Марковская модель 1 -го порядка
AIC 3290410.9096070216
BIC 3290501.0051205363
Марковская модель 2 -го порядка
AIC 3267764.051151953
BIC 3268142.4523087153
Марковская модель 3 -го порядка
AIC 3257974.5465277163
BIC 3259506.1702574673
Марковская модель 4 -го порядка
AIC 3255188.2092244066
BIC 3261332.723246113
Марковская модель 5 -го порядка
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-158-6c266ffd3b81> in <cell line: 1>()
      3   params = estimate_markov_model(order=i, sequences=train_pieces)
      4   k = indep_params(alphabet, order=i)
----> 5   lnL = ln_likelihood_Markov(params, order=i, sequences=test_pieces)
      6 
      7   bic = BIC(len(train_pieces), k, lnL)

<ipython-input-133-bbbb0db358eb> in ln_likelihood_Markov(probabilities, order, sequences)
      6     for i in range(order):
      7       #print(seq[0:i+1])
----> 8       L+=math.log(float(probabilities[i][seq[0:i+1]]), math.e)
      9     #print("-------")
     10     for i in range(order, len(seq)):

ValueError: math domain error

С марковской моделью пятого порядка возникла ошибка, так как в тренировочной выборке не встретился один из 5-меров, а его частота была приравнена 0. Но в тестовой выборке этот 5-мер возник, а логарифм от него взять не вышло. Можно было бы добавить "псевдочастоты", равные не 0, а, например, 10^(-10). Это бы несильно повлияло на остальную статистику, но позволило бы избежать ошибки. Но так как по BIC уже видно, что модель четвертого порядка уступает третьей, я решила остановится.

AIC

Бернуллиевская модель: 3331344.947942344

Марковская модель 1-го порядка: 3290410.9096070216

Марковская модель 2-го порядка: 3267764.051151953

Марковская модель 3-го порядка: 3257974.5465277163

Марковская модель 4-го порядка: 3255188.2092244066 (Победитель!)

BIC

Бернуллиевская модель: 3331362.967045047

Марковская модель 1-го порядка: 3290501.0051205363

Марковская модель 2-го порядка: 3268142.4523087153

Марковская модель 3-го порядка: 3259506.1702574673 (Победитель!)

Марковская модель 4-го порядка: 3261332.723246113

По AIC оценке геном лучше всего описывается марковской моделью 4-го порядка, по BIC - марковской моделью 3-го порядка.