{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Lab 12 - RNA Sequencing through Expectation Maximization\n", "\n", "#### Authors:\n", "\n", "v1.0 (2014 Fall) Rishi Sharma \\*\\*\\*, Sahaana Suri \\*\\*\\*, Paul Rigge \\*\\*\\*, Kangwook Lee \\*\\*\\*, Kannan Ramchandran \\*\\*\\*
\n", "v1.1 (2015 Fall) Kabir Chandrasekher \\*\\*, Max Kanwal \\*\\*, Kangwook Lee \\*\\*\\*, Kannan Ramchandran \\*\\*\\*
\n", "v1.2 (2016 Spring) Kabir Chandrasekher, Tony Duan, David Marn, Ashvin Nair, Kangwook Lee, Kannan Ramchandran" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Table of Contents\n", "\n", "\n", "- [Introduction](#Introduction)\n", "- [MLE for a simple model](#Question-1----Simple-Model)\n", "- [MLE for a harder model](#Question-2----Harder-Model)\n", "- [EM algorithm for the harder model](#Question-3----EM-Algorithm)\n", "- [References](#References)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Introduction\n", "\n", "The problem of [RNA sequencing](http://en.wikipedia.org/wiki/RNA-Seq) is to figure out how much and what type of RNA is present in a genome at a given moment in time. It has many applications including genome annotation, comprehensive identification of fusions in cancer, discovery of novel isoforms of genes, and genome sequence assembly [[1][2]](#References).\n", "\n", "For our purposes, we'll formulate the problem as follows: given a set of short reads that are sampled from a set of larger genes, how can we find the relative abundance of each gene? That is, given just the short reads, how do we know how frequently each original gene occurs? This process is depicted in Figure 1. (Aside: in the actual paper, these \"genes\" are actually \"transcripts,\" but that's not relevant for us.)\n", "\n", "\n", "\n", "####
Figure 1: We want to use the reads to guess the underlying proportion.
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It turns out we can use some methods we learned in class (MLE & EM) to solve this problem -- let's try it out.\n", "\n", "We assume that all genes are of the same length, $\\ell_t$, and all reads are of the same length, $\\ell_x$. Then, we assume the following Bayesian generative model:\n", "\n", "1. A read comes from a randomly chosen gene $t_i$\n", "2. A read's starting point is randomly chosen among all possible $\\ell_t$ starting positions in that gene\n", "\n", "Given a set of reads $X = \\{X_1 \\ldots X_n\\}$, we want to figure out what distribution $\\rho = \\{ \\rho_1 \\ldots \\rho_m \\}$ over the genes was most likely to give us the reads $X$. To do this, we'll need to maximize the following likelihood function:\n", "\n", "$$ L(\\rho) = \\prod_{i=1}^{N}{ P(X_i|\\rho) } $$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Question 1 (Optional) -- Simple Model\n", "\n", "To make life easier, we're first going to assume no read is ambiguous. That is -- given a read, we can immediately tell which gene it came from. (In practice, this means we would have to know the chart mapping each color to a gene, as in Figure 1.)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1a. Suppose you are given a read $X_i$ -- what is $P(X_i|\\rho)$?\n", "\n", "Your solution should take both the gene lengths and the read lengths into consideration. Denote the probability of seeing a specific gene as $\\rho_{t_i}$.\n", "\n", "Hint: how many possible starting positions exist for $X_i$?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Your answer here*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1b. Assume that you have two genes. Find the MLE of $\\rho$ if you find $x$ reads compatible with gene $1$, and $n-x$ reads compatible with gene $2$. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Your answer here*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1c. Assume you have $M$ genes. Out of $n$ reads, $x_i$ reads are compatible with gene $i$, where $\\sum_{i=1}^{M}{x_i} = n$. Find the maximum likelihood estimator of $\\rho$. \n", "\n", "Hint: you might just be able to make an \"educated guess\" from your answer above. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Your answer here.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Question 2 -- Harder Model\n", "\n", "Life gets harder when you allow for ambiguous reads. Going back to the figure above, we can imagine a case where we don't know which color a read belongs to, but we have a rough idea of the possible colors it could have been. See the modified figure below.\n", "\n", "\n", "####
Figure 2
\n", "In this portion, we'll consider a general problem where a read is aligned with possibly more than one gene. \n", "\n", "First, we define a compatibility matrix $A \\in \\{0,1\\}^{n \\times m} = \\{a_{i,j}\\}$, where $a_{i,j}$ is $1$ if read $i$ is aligned with gene $j$, $0$ otherwise. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a motivating example, let's assume we have $3$ genes and $5$ reads aligned as follows:\n", "\n", "(ref: pp16-17 Pachter 2011)\n", "\n", "\n", "####
Figure 3: Each read is a subset of some gene, and it can be compatible with multiple genes.
\n", "\n", "### 2a. Find the compatibility matrix $A$ for the above figure." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Your answer here.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2b. Given an arbitrary compatibility matrix, write an expression to find the likelihood function for $\\rho$.\n", "\n", "You'll have to tweak your solution to the last portion by carefully considering how you can represent $P(X_i|\\rho)$ given the compatibility matrix $A$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Your answer here.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Question 3 -- EM Algorithm\n", "\n", "In general, it is not easy to find the exact maximum likelihood estimator of $\\rho$ if ambiguous reads exist. Instead, we can rely on iterative methods that we hope will converge to the true value. One way to go about this is via expectation maximization (EM), as you have seen in class. \n", "\n", "To recap, [here](http://ai.stanford.edu/~chuongdo/papers/em_tutorial.pdf) is a short tutorial that does a wonderful job of explaining all that you need to know about EM [[3]](#References)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For our purposes, here is an EM algorithm that can be used. You'll be implementing it shortly, so read it carefully and understand why it works. \n", "\n", "1. Initialize $\\rho = (\\frac{1}{M}, \\frac{1}{M}, \\ldots, \\frac{1}{M})$, all genes are equally probable.\n", "2. Find the compatibility matrix $A$.\n", "3. Repeat the following until $\\rho$ converges:
\n", " a. Each reading $i$ corresponds to the $i$th row of $A$. Call this $\\mathcal{I}_i$.
\n", " b. Put the values of $\\rho$ in $\\mathcal{I}_i$ where $\\mathcal{I}_i$ is not zero. Then normalize the vector and replace the $i$th row of $A$ with the normalized vector.
\n", " c. Replace $\\rho$ such that for each gene $j$, $\\rho_j = \\frac{1}{N}\\sum_{i=1}^{N}{A_{i,j}}$\n", "\n", "The following figure is a visual representation of the algorithm (Ref: p17 Pachter 2011) [[1]](#References)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "####
Figure 4: Visualization of the EM algorithm we will use.
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is a lot to digest at once, so let's only look at the first step to begin with.\n", "\n", "There are three possible genes to analyze (red, green, blue). There are five reads (a,b,c,d,e) that align with different genes. Initially, you assume a uniform prior.\n", "\n", "1. E step. Reads are proportionately assigned to each of the genes they could have come from, according to the current distribution $\\rho$.\n", "2. M step. The distribution $\\rho$ is recalculated proportionally from the assigned read counts from the E step.\n", "\n", "For example, the abundance of red after the first M step is estimated by\n", "\n", "$$\\rho_1 = 0.47 = \\frac{0.33 + 0.5 + 1 + 0.5}{5}$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3a. Explain the above EM algorithm in your own words. Will it always find the MLE for $\\rho$? " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Your answer here.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3b. Implement the above EM algorithm. Run it with the given set of reads & genes. What is your estimated $\\rho$?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's begin by with a toy example. We'll start by making the relevant imports..." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from __future__ import division\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we'll define our genes." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "transcripts = ['ATCTCGACGCACTGC', 'GAGTTCGAACTCTTC', 'AGAGTTCCAGTGTCA', 'AAAGCTCACTGCGGA', 'AGCGATATCAGAGTD']\n", "M = len(transcripts)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We'll randomly generate the true distribution $\\rho$. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "rho = np.random.rand(M)\n", "rho /= sum(rho)\n", "plt.bar(np.arange(M) + 0.6, rho, width=0.8)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We'll then pick 1000 random reads of length 5 each." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def random_read( s, rho, L ):\n", " chosen_seq = np.random.choice(s, p=rho)\n", " start_idx = np.random.randint(0, len(chosen_seq) - L)\n", " end_idx = start_idx + L\n", " return chosen_seq[ start_idx:end_idx ]\n", " \n", "N = 1000 # Number of reads\n", "L = 5\n", "\n", "reads = []\n", "for i in range(N):\n", " reads.append( random_read(transcripts, rho, L) )\n", " \n", "print('First 10 reads...', reads[0:10])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the code below, run the EM algorithm for 100 iterations and report your estimated distribution of $\\rho$." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "N_iter = 100 #number of E/M iterations\n", "\n", "def find_all_alignments(s, read):\n", " tmp = []\n", " for j in range(len(s)):\n", " if read in s[j]:\n", " tmp.append(j)\n", " return tmp\n", "\n", "# A: Compatibility Matrix. \n", "# Note: You can choose to represent this matrix in whatever form is easiest for your calculations\n", "# The form we are pushing you towards here is just how we chose to implement the algorithm\n", "A = []\n", "for each_read in reads:\n", " A.append( find_all_alignments(transcripts, each_read) )\n", "\n", "hidden_state_prior = np.zeros([N, M])\n", "rho_est = np.array([1/5, 1/5, 1/5, 1/5, 1/5])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "for i in range(N_iter):\n", " \n", " # Your code here\n", " # 1. E step\n", " # 2. M step\n", " \n", " pass" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Your estimated distribution should look similar to the real distribution." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "print('(real) rho', rho)\n", "print('(est.) rho', rho_est)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "plt.bar(np.arange(M) + 0.6, rho, color='blue', width=0.4, label='Real')\n", "plt.bar(np.arange(M) + 1, rho_est, color='green', width=0.4, label='Estimated')\n", "plt.legend()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3c. Run the same EM algorithm on our bigger dataset." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's try running the same algorithm on much more data. Here we have a dataset of 150 transcripts of length varying from 4 to 19. We've gathered 10000 reads from exactly 5 of them -- can you recover which 5 transcripts we gathered the reads from?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "M, N = 150, 10000\n", "transcripts = np.load('transcripts.npy')\n", "reads = np.load('reads.npy')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Your answer here." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Congratulations -- you've just finished your last lab for EE 126!\n", "\n", "Take a minute to appreciate what you've accomplished throughout the semester. This class wasn't easy, but hopefully you've learned a lot! Come see us if you'd like some help figuring out where to go from here." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## References\n", "\n", "[1] L. Pachter. Models for transcript quantification from RNA-Seq. available at arXiv:1104.3889 [q-bio.GN], 2011.
\n", "[2] A. Roberts and L. Pachter, RNA-Seq and find: entering the RNA deep field, Genome Medicine, 3 (2011), 74.
\n", "[3] C. Do and S. Batzoglou, What is the expectation maximization algorithm? Nature Biotechnology, 26 (2008), 8." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3.0 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.1" } }, "nbformat": 4, "nbformat_minor": 0 }