序列比对(九)——从掷骰子谈HMM

原创:hxj7

从本文开始,到了序列比对的第二部分,主要是介绍HMM以及其在序列比对中的基础应用。

前面八篇文章介绍了动态规划在序列比对中的基础应用。从本文开始,开始介绍HMM(隐马尔可夫模型)。

Markov链

首先我们先介绍马尔可夫链(Markov链),这个大家可能都熟悉,高中数学中就学过。简单来说,Markov链就是一系列状态构成,每一个状态出现的概率只与它前一个状态有关。
具体地说,假设有一系列状态\pi,依次由\pi_1,\pi_2,...,\pi_L构成,那么在\pi_1,\pi_2,...,\pi_{i-1}已经发生的情况下,\pi_i发生的概率只与\pi_{i-1}相关。即:
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ P(\pi_i|\pi_1,\pi_2,...,\pi_{i-1}) = P(\pi_i|\pi_{i-1})
由此,我们可以推导出:
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ P(\pi) = P(\pi_1,\pi_2,\pi_3,...\pi_L)
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ = P(\pi_1)P(\pi_2|\pi_1)P(\pi_3|\pi_1,\pi_2)...P(\pi_L|\pi_1,\pi_2,...,\pi_{L-1})
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ = P(\pi_1)P(\pi_2|\pi_1)P(\pi_3|\pi_2)...P(\pi_L|\pi_{L-1})

为了建模的方便,一般还会假设一个初始状态\pi_0,则上面的公式变成:
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ P(\pi)= P(\pi_0)P(\pi_1|\pi_0)P(\pi_2|\pi_1)P(\pi_3|\pi_2)...P(\pi_L|\pi_{L-1})

为了更形象说明,以投骰子为例来说,假设我们有下面这张图:


image

图片引自《生物序列分析》

这张图是说有两种骰子,一种是“公平的”(Fair,简写F),一种是“作弊的”(Loaded,简写L)。F骰子掷出1-6的概率是一样的,而L骰子掷出6的概率为0.5,其余1-5的概率都是0.1。
此外,如果这次使用F骰子,那么下次仍然使用F骰子的概率是0.95,换用L骰子的概率是0.05。相反,如果这次使用L骰子,那么下次仍然使用L骰子的概率是0.9,换用F骰子的概率是0.1。

状态向量

上面的介绍中,使用骰子的过程就是一个简单的Markov链。令\pi为一系列掷骰子的状态,则\pi_i\in\{F, L\}。F为公平骰子,L为作弊骰子。Markov链中所有可能的状态构成的集合(向量),即此处的\{F, L\}。称为状态向量。

符号向量

上图中,不同骰子状态下,掷出1-6的概率不一样,假设在第i次投掷中,使用的骰子状态是\pi_i,而掷出的结果(符号)为x_i,那么x_i\in\{1,2,3,4,5,6\}。Markov链中所有可能的结果(符号)构成的集合(向量),即此处的\{1,2,3,4,5,6\},称为符号向量。

转移概率

为了方便,我们记a_{kl} = P(\pi_i=l|\pi_{i-1}=k),称为从状态k到状态l的转移概率。比如:
\ \ \ a_{FF}=P(\pi_i=F|\pi_{i-1}=F) = 0.95;\ \ \ \ \ \ \ \ a_{FL}=P(\pi_i=L|\pi_{i-1}=F) = 0.05
\ \ \ a_{LL}=P(\pi_i=L|\pi_{i-1}=L) = 0.9;\ \ \ \ \ \ \ \ \ \ \ a_{LF}=P(\pi_i=F|\pi_{i-1}=L) = 0.1

转移矩阵

不同状态之间互相转移的概率可以构成一个矩阵,成为转移矩阵。比如:

F L
F 0.95 0.05
L 0.1 0.9
初始向量

有了转移概率的记号,那么P(\pi)的计算公式可以写成:
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ P(\pi)= P(\pi_0)P(\pi_1|\pi_0)P(\pi_2|\pi_1)P(\pi_3|\pi_2)...P(\pi_L|\pi_{L-1})
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ = P(\pi_0)a_{\pi_0\pi_1}a_{\pi_1\pi_2}a_{\pi_2\pi_3}...a_{\pi_{L-1}\pi_L}
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =P(\pi_0)\prod_{i=0}^{L-1} a_{\pi_i\pi_{i+1}}
其中,\pi_0就是状态0,实际上它并不存在,只是为了建模的方便假设它存在。从状态0到其他状态的转移概率可以称为初始概率,所有可能的初始概率构成初始向量。比如:

F L
0 0.9 0.1
发射概率

不同骰子状态下某一符号出现的概率是不一样的,以骰子为例,公平骰子和作弊骰子掷出6的概率是不一样的,不光是6,掷出1-5的概率也是不一样的:
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ P(x_i=k|\pi_i=F)=1/6, \ \ \ \ \ \ \ \ \ \ \ k=1,2,...,6
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ P(x_i=k|\pi_i=L)=0.1, \ \ \ \ \ \ \ \ \ \ \ \ k=1,2,...,5
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ P(x_i=6|\pi_i=L)=0.5
我们将某一状态l下符号k出现的概率称为发射概率,记为e_l(k),即
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ e_l(k) = P(x_i=k|\pi_i=l)

发射矩阵

不同状态下不同符号的发射概率可以构成一个矩阵,成为发射矩阵,如:

1 2 3 4 5 6
F 1/6 1/6 1/6 1/6 1/6 1/6
L 0.1 0.1 0.1 0.1 0.1 0.5

隐马尔可夫模型

什么叫隐马尔可夫模型呢?还以上图为例。假设别人一共投掷了300次,那么我们可以看到一个长度为300的符号序列x,其中x_i\in\{1,2,3,4,5,6\}。但是我们并不知道每一次投掷用的是F骰子还是L骰子,也就是说我们不知道每一次骰子的状态。这种符号序列已知,而状态序列被隐藏的模型就叫隐马尔可夫模型。

为了后续深入学习隐马模型,我们首先得写一个程序,能根据转移矩阵以及发射矩阵生成一个随机的状态序列以及相应的符号序列。

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

typedef char State;
typedef char Result;
State state[] = {'F', 'L'};   // 所有的可能状态
Result result[] = {'1', '2', '3', '4', '5', '6'};   // 所有的可能符号
double init[] = {0.9, 0.1};    // 初始状态的概率向量
double emission[][6] = {   // 发射矩阵:行对应着状态,列对应着符号
  1.0/6, 1.0/6, 1.0/6, 1.0/6, 1.0/6, 1.0/6,
  0.1, 0.1, 0.1, 0.1, 0.1, 0.5
};
double trans[][2] = {   // 转移矩阵:行和列都是状态
  0.95, 0.05,
  0.1, 0.9
};
const int nstate = 2;
const int nresult = 6;
State* rst;   // 一串随机状态序列
Result* rres;  // 一串随机符号序列

int random(double* prob, const int n);
void randSeq(State* st, Result* res, const int n);
void printState(State* st, const int n);
void printResult(Result* res, const int n);

int main(void) {
  int i;
  int n = 300;
  int ll = 60;
  int nl, nd;
  if ((rst = (State*) malloc(sizeof(State) * (n))) == NULL || \
      (rres = (Result*) malloc(sizeof(Result) * (n))) == NULL) {
    fputs("Error: out of space!\n", stderr);
    exit(1);
  }
  randSeq(rst, rres, n);
  nl = n / ll;
  nd = n % ll;
  for (i = 0; i < nl; i++) {
    printf("Rolls\t");
    printResult(rres + ll * i, ll);
    printf("Die\t");
    printState(rst + ll * i, ll);
    printf("\n");
  }
  if (nd > 0) {
    printf("Rolls\t");
    printResult(rres + ll * i, nd);
    printf("Die\t");
    printState(rst + ll * i, nd);
    printf("\n");
  }
  free(rst);
  free(rres);
}

// 根据一个概率向量从0到n-1随机抽取一个数
int random(double* prob, const int n) {
  int i;
  double p = rand() / 1.0 / (RAND_MAX + 1);
  for (i = 0; i < n - 1; i++) {
    if (p <= prob[i])
      break;
    p -= prob[i];
  }
  return i;
}

// 根据转移矩阵和发射矩阵生成一串随机状态和符号
void randSeq(State* st, Result* res, const int n) {
  int i, ls, lr;
  srand((unsigned int) time(NULL));
  ls = random(init, nstate);
  lr = random(emission[ls], nresult);
  st[0] = state[ls];
  res[0] = result[lr];
  for (i = 1; i < n; i++) {
    ls = random(trans[ls], nstate);
    lr = random(emission[ls], nresult);
    st[i] = state[ls];
    res[i] = result[lr];
  }
}

void printState(State* st, const int n) {
  int i;
  for (i = 0; i < n; i++)
    printf("%c", st[i]);
  printf("\n");
}

void printResult(Result* res, const int n) {
  int i;
  for (i = 0; i < n; i++)
    printf("%c", res[i]);
  printf("\n");
}

(公众号:生信了)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容