{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"from collections import Counter,defaultdict\n",
"import random\n",
"import gzip\n",
"import textwrap"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def make_trigrams(filename):\n",
"\n",
" #returns list of words in file\n",
" with gzip.open(filename) as f: words = f.read().split()\n",
"\n",
" trigrams = defaultdict(list)\n",
" \n",
" bigram=tuple(words[:2])\n",
" startwords=[bigram]\n",
" \n",
" for w in words[2:] + words[:2]:\n",
" #keys of trigram dict are tuples, values are lists\n",
" trigrams[bigram].append(w)\n",
" if bigram[0].endswith('.') and bigram[1][0].isupper():\n",
" startwords.append((bigram[1],w))\n",
" bigram=(bigram[1],w)\n",
"\n",
" return trigrams,startwords"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def random_text(trigrams, startwords, num_words=100):\n",
" \n",
" current_pair = random.choice(startwords)\n",
" random_text = list(current_pair)\n",
" \n",
" # continue past num_words until ends in . \n",
" while len(random_text)< num_words or not random_text[-1].endswith('.'):\n",
" next = random.choice(trigrams[current_pair])\n",
" random_text.append(next)\n",
" current_pair = (current_pair[1], next)\n",
" # avoid long loops if too few periods in training text\n",
" if len(random_text) > 2*num_words: random_text[-1] += '.'\n",
" \n",
" return textwrap.fill(' '.join(random_text))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The source text files for the below can be found here:\n",
"\n",
"1. sherlock.txt.gz\n",
"2. oz.txt.gz\n",
"3. di.txt.gz\n",
"4. shakespeare.txt.gz"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"trigrams_sh,startwords_sh=make_trigrams('sherlock.txt.gz')"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[(('of', 'the'), 700),\n",
" (('in', 'the'), 479),\n",
" (('to', 'the'), 297),\n",
" (('I', 'have'), 247),\n",
" (('that', 'I'), 245),\n",
" (('at', 'the'), 224),\n",
" (('upon', 'the'), 195),\n",
" (('and', 'I'), 191),\n",
" (('to', 'be'), 189),\n",
" (('and', 'the'), 186)]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#most common bigram keys\n",
"sorted([(bi,len(trigrams_sh[bi])) for bi in trigrams_sh],key=lambda x: x[1],reverse=True)[:10]"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[(('It', 'was'), 91),\n",
" (('It', 'is'), 88),\n",
" (('I', 'have'), 49),\n",
" (('He', 'was'), 38),\n",
" (('There', 'was'), 31),\n",
" (('There', 'is'), 28),\n",
" (('I', 'am'), 27),\n",
" (('I', 'was'), 27),\n",
" (('I', 'had'), 26),\n",
" (('On', 'the'), 22)]"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Counter(startwords_sh).most_common(10) #starts of sentences"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"548"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(set(trigrams_sh[('of','the')])) #distinct continuations from \"of the ...\""
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"We both sprang in, and away we went to the ventilator and to carry out\n",
"my orders to the end of our depositors. One of the windows on either\n",
"side of the matter struck me that the affair of the garden. Perhaps\n",
"the villain was softened by the incident, as far as we entered he made\n",
"friends in the Museum itself during the last item. \"Well,\" he said,\n",
"but at that deadly black shadow wavering down upon me, and Godfrey\n",
"Norton was evidently an important factor in the habit of standing on\n",
"it, which seemed quite exaggerated in its details that it had dropped\n",
"asleep, and indeed was nodding myself, when he was still, as ever,\n",
"deeply attracted by my friend's subtle powers of observation and\n",
"inference.\n"
]
}
],
"source": [
"print random_text(trigrams_sh,startwords_sh) #random sherlock"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"trigrams_di,startwords_di=make_trigrams('di.txt.gz')\n",
"trigrams_oz,startwords_oz=make_trigrams('oz.txt.gz')"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Then the Tin Woodman swung his arm and managed to scramble to the King\n",
"of the Emerald City. But my action angered the Wicked Witch is Wicked\n",
"--tremendously Wicked -and ought to be a coward,\" said the Scarecrow.\n",
"\"And I want him to give me courage?\" asked the girl. \"That will not\n",
"send me back to say to me.\" \"This is the great Kansas prairies, with\n",
"Uncle Henry, who was weeping in a cheerful voice and went back to\n",
"Kansas unless you do not want to go any other country, be it ever so\n",
"much disappointed; and the country of the East? Dorothy was tired by\n",
"the brilliancy of the East blue was the happiest man on earth; but no\n",
"one has ever destroyed her before, so I suppose there never will be,\n",
"for they will fit me,\" she said sadly, \"for Oz will send you back to\n",
"Kansas and Aunt Em had just started to cross the hill and set herself\n",
"to sleep.\n"
]
}
],
"source": [
"print random_text(trigrams_oz,startwords_oz) #random Oz"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"But when a long time, after such dissolutions, to cause others to\n",
"encourage their migrations hither, and raising the conditions of new\n",
"Appropriations of Lands. He has dissolved Representative Houses\n",
"repeatedly, for opposing with manly firmness his invasions on the\n",
"Inhabitants of these States: For cutting off our Trade with all parts\n",
"of the United States of America, in General Congress, Assembled,\n",
"appealing to the separation. We hold these truths to be tried for\n",
"pretended offences: For abolishing the free System of English Laws in\n",
"a neighbouring Province, establishing therein an Arbitrary government,\n",
"and enlarging its Boundaries so as to them and the amount and payment\n",
"of their offices, and the State of Great Britain, is and ought to be\n",
"self-evident, that all political connection between them and the State\n",
"of Great Britain, is and ought to be Free and Independent States, they\n",
"have full Power to levy War, conclude Peace contract Alliances,\n",
"establish Commerce, and to assume among the powers of the good People\n",
"of these Oppressions We have appealed to their Acts of pretended\n",
"Legislation: For quartering large bodies of armed troops among us: For\n",
"protecting them, by a mock Trial from punishment for any Murders which\n",
"they should.\n"
]
}
],
"source": [
"print random_text(trigrams_di,startwords_di) #random declaration of independence"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"He has abdicated Government here, by declaring us out of sight. The\n",
"Wicked Witch of the Mice had given up at last, he walked to the little\n",
"company set off upon the bank and gazed wistfully at the end of her\n",
"nose, and having said one of those great whirlwinds arose, mighty\n",
"enough to look at all afraid, although he was made of silk into proper\n",
"shape the girl they left a round, shining mark, as Dorothy was\n",
"thinking again, and these tears did not even bark in return. In this\n",
"country alone, and cannot love. I pray you to any place in order to\n",
"start, for she did not take her long walk in, for they immediately\n",
"took out their substance.\n"
]
}
],
"source": [
"trigrams_oz_di= dict(trigrams_oz.items()+trigrams_di.items())\n",
"for bigram in set(trigrams_oz) & set (trigrams_di):\n",
" trigrams_oz_di[bigram] = trigrams_oz[bigram] + trigrams_di[bigram]\n",
"startwords_oz_di = startwords_oz + startwords_di\n",
" \n",
"print random_text(trigrams_oz_di,startwords_di) #mashup of declaration and oz"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"trigrams_sk,startwords_sk=make_trigrams('shakespeare.txt.gz') "
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Enter servants Take hence this body, consecrate to thee, Thine by thy\n",
"waggon wheel Trot, like a rough colt; he knows you not. MENENIUS. I\n",
"think of that joy; Or in the earth. DOLABELLA. Most noble Antony, Let\n",
"not the double majesties This friendly treaty of our success. Some\n",
"dishonour we had all such wives, that the affrighted globe Should yawn\n",
"at alteration. EMILIA. [Within.] What, ho! Peace here; grace and\n",
"faults are loved of more value Than stamps in gold, like heathen gods,\n",
"Shone down the gate? VINCENTIO. Is Signior Lucentio that his fault I\n",
"should meet the King.\n"
]
}
],
"source": [
"print random_text(trigrams_sk,startwords_sk) #random shakespeare"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"trigrams_sh_sk= dict(trigrams_sh.items()+trigrams_sk.items())\n",
"for bigram in set(trigrams_sh) & set (trigrams_sk):\n",
" trigrams_sh_sk[bigram] = trigrams_sh[bigram] + trigrams_sk[bigram]\n",
"startwords_sh_sk = startwords_sh + startwords_sk"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Oakshott, of Brixton Road, where she comes, and I'll pay thee for thy\n",
"ruler. SOMERSET. O monstrous villain! Re-enter BIONDELLO, with\n",
"LUCENTIO disguised as drawers FALSTAFF. Peace, good Doll! Do not you\n",
"Sir John and Robert, be ready here hard by with stiff unbowed knee,\n",
"Disdaining duty that I lack'd it. But look, the morn, And, having\n",
"sworn too hard-a-keeping oath, Study to break promise with me. [To\n",
"ARIEL] Thou shalt not choose but branch now. Since their more piquant\n",
"details have drawn a net Than amply to imbar their crooked tides\n",
"Usurp'd from you as much more, and ten miles of town, chemistry\n",
"eccentric, anatomy unsystematic, sensational literature and crime\n",
"records unique, violin-player, boxer, swordsman, lawyer, and self-\n",
"poisoner by cocaine and ambition, The soldier's pole is fall'n! Young\n",
"boys and wenches must I select from all; the rest TALBOT.\n"
]
}
],
"source": [
"print random_text(trigrams_sh_sk,startwords_sh) #mashup of shakespeare and sherlock"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Below the simulation of this example:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
""
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from IPython.display import Image\n",
"Image(open('m7.png').read())"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"mchain={0:{1:.5, 7:.5}, 1:{}, 2:{3:.5}, 3:{1:.5},\n",
" 4:{6:.8}, 5:{}, 6:{5:.3}, 7:{2:.2, 4:.4}}"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"T=array([[mchain[m][n] if n in mchain[m]\n",
" else round(1.-sum(mchain[m].values()),4) if m==n\n",
" else 0.\n",
" for n in mchain ] for m in mchain])"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0. , 0.5, 0. , 0. , 0. , 0. , 0. , 0.5],\n",
" [ 0. , 1. , 0. , 0. , 0. , 0. , 0. , 0. ],\n",
" [ 0. , 0. , 0.5, 0.5, 0. , 0. , 0. , 0. ],\n",
" [ 0. , 0.5, 0. , 0.5, 0. , 0. , 0. , 0. ],\n",
" [ 0. , 0. , 0. , 0. , 0.2, 0. , 0.8, 0. ],\n",
" [ 0. , 0. , 0. , 0. , 0. , 1. , 0. , 0. ],\n",
" [ 0. , 0. , 0. , 0. , 0. , 0.3, 0.7, 0. ],\n",
" [ 0. , 0. , 0.2, 0. , 0.4, 0. , 0. , 0.4]])"
]
},
"execution_count": 51,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"T"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([ 1., 1., 1., 1., 1., 1., 1., 1.])"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sum(T,axis=1)"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([ 0. , 0. , 0.2, 0.2, 0.6, 0.6, 0.6, 1. ])"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"T[7].cumsum()"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([4, 7, 4, 7, 4, 7, 4, 2, 4, 7])"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"digitize(rand(10),T[7].cumsum())"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Counter({4: 40182, 7: 39752, 2: 20066})"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from collections import Counter\n",
"Counter(digitize(rand(100000),T[7].cumsum()))"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"n=len(T)\n",
"results={1:[],5:[]}\n",
"for t in xrange(100000): #trials\n",
" m=0 #start at 0\n",
" for k in xrange(1,10000): #just much bigger than likely path\n",
" #pull next state from probability distribution given by m'th row\n",
" m=digitize([rand()],T[m].cumsum())[0]\n",
" if m==5 or m==1:\n",
" results[m].append(k)\n",
" break"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(66670, 33330)"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(results[1]),len(results[5])"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[2.41, 7.254]"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[round(m,3) for m in mean(results[1]),mean(results[5])]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Finally, some examples of powers of matrices"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"take nth power of matrix either with\n",
"\n",
" linalg.matrix_power(T,n)\n",
"or\n",
"\n",
" reduce(dot,[T]*n)\n",
"(gives same result, but `linalg.matrix_power()` is optimized so will be much faster on big matrices). The pylab inline option in the EPD python distribution seems to call in the `linalg` module by default, so it's possible to say just `matrix_power()`, as below."
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0. , 0.667, 0. , 0. , 0. , 0.333, 0. , 0. ],\n",
" [ 0. , 1. , 0. , 0. , 0. , 0. , 0. , 0. ],\n",
" [ 0. , 1. , 0. , 0. , 0. , 0. , 0. , 0. ],\n",
" [ 0. , 1. , 0. , 0. , 0. , 0. , 0. , 0. ],\n",
" [ 0. , 0. , 0. , 0. , 0. , 1. , 0. , 0. ],\n",
" [ 0. , 0. , 0. , 0. , 0. , 1. , 0. , 0. ],\n",
" [ 0. , 0. , 0. , 0. , 0. , 1. , 0. , 0. ],\n",
" [ 0. , 0.333, 0. , 0. , 0. , 0.667, 0. , 0. ]])"
]
},
"execution_count": 52,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"around(matrix_power(T,30),3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that the first row shows that starting from state 0, ultimately state 1 is reached 2/3 of the time and state 5 is reached 1/3 of the time, as expected. From the next three rows we see that starting any of states 1,2,3 state 1 is always reached, and so on. \n",
"\n",
" Finally noticed that `T**n` just takes the nth power of the entries of the matrix one by one, which is usually (but not always) not what is wanted:"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ],\n",
" [ 0. , 1. , 0. , 0. , 0. , 0. , 0. , 0. ],\n",
" [ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ],\n",
" [ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ],\n",
" [ 0. , 0. , 0. , 0. , 0. , 0. , 0.001, 0. ],\n",
" [ 0. , 0. , 0. , 0. , 0. , 1. , 0. , 0. ],\n",
" [ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ],\n",
" [ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ]])"
]
},
"execution_count": 53,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"around(T**30,3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To see the effect of taking powers of a matrix, consider a random 4x4 matrix:"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0.37191866, 0.19514006, 0.59574904, 0.21311382],\n",
" [ 0.22453282, 0.44280837, 0.32729572, 0.25502435],\n",
" [ 0.06934085, 0.50455362, 0.09645712, 0.12621279],\n",
" [ 0.47506432, 0.14128696, 0.3994524 , 0.22011466]])"
]
},
"execution_count": 55,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"T=rand(4,4) #random 4x4 matrix\n",
"T"
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([ 1.37592158, 1.24966127, 0.79656438, 1.23591834])"
]
},
"execution_count": 56,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sum(T,axis=1) #sum along the rows"
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0.27030513, 0.14182499, 0.43298182, 0.15488806],\n",
" [ 0.17967495, 0.35434272, 0.26190755, 0.20407478],\n",
" [ 0.0870499 , 0.63341223, 0.12109143, 0.15844644],\n",
" [ 0.38438164, 0.11431739, 0.3232029 , 0.17809806]])"
]
},
"execution_count": 57,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"T /= sum(T,axis=1)[:,None] #divide by the sums along the rows so they sum to 1\n",
"T"
]
},
{
"cell_type": "code",
"execution_count": 58,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([ 1., 1., 1., 1.])"
]
},
"execution_count": 58,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sum(T,axis=1) #verify"
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0.19577441, 0.38055306, 0.2566729 , 0.16699963],\n",
" [ 0.21347519, 0.3402659 , 0.26827334, 0.17798556],\n",
" [ 0.20878324, 0.33160484, 0.26945995, 0.19015196],\n",
" [ 0.22103271, 0.32010284, 0.29306977, 0.16579469]])"
]
},
"execution_count": 59,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"T.dot(T) # this gives T^2"
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0.20782962, 0.34428263, 0.26949214, 0.17839562],\n",
" [ 0.21060825, 0.34112132, 0.27156014, 0.17671029],\n",
" [ 0.21256365, 0.33952935, 0.27133612, 0.17657088],\n",
" [ 0.20650086, 0.34936126, 0.26861406, 0.17552382]])"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"T.dot(T).dot(T) # this gives T^3"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0.21006764, 0.34256281, 0.27044784, 0.17692171],\n",
" [ 0.20978292, 0.34295394, 0.27052868, 0.17673446],\n",
" [ 0.20995235, 0.34250933, 0.2708862 , 0.17665212],\n",
" [ 0.20944067, 0.34328946, 0.27016814, 0.17710173]])"
]
},
"execution_count": 61,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"T.dot(T).dot(T).dot(T) # this gives T^4"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We see that the rows are already converging after a few iterations (recall the largest eigenvalue of the matrix is always 1, and the convergence is governed by the size of the second eigenvalue, see these notes. The first row gives the probability of landing at the other states starting from the first state, the second row for starting at the second state, and so on. Equal rows means that the probabilities of where one ends up become independent of where one started (that's what's meant by the steady state distribution). After twelve iterations, the probabilities are all the same to eight significant digits:"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0.20982798, 0.34281091, 0.27054469, 0.17681641],\n",
" [ 0.20982798, 0.34281091, 0.27054469, 0.17681641],\n",
" [ 0.20982798, 0.34281091, 0.27054469, 0.17681641],\n",
" [ 0.20982798, 0.34281091, 0.27054469, 0.17681641]])"
]
},
"execution_count": 62,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"matrix_power(T,12)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"From here it's possible to take any row as the stationary state v (corresponds to starting from a single state), or we could imagine starting from an equiprobability state w=[1./4,1./4,1./4,1./4] (gives the same result since all the rows are the same at this point):"
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([ 0.20982798, 0.34281091, 0.27054469, 0.17681641])"
]
},
"execution_count": 67,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w=ones(4)/4 #all components equal to 1/4.\n",
"v=w.dot(matrix_power(T,12))\n",
"v"
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 25.1509253232\n",
"1 1.86295622688\n",
"2 0.543004876818\n",
"3 0.0616561134596\n",
"4 0.00908178780218\n",
"5 0.00110233172968\n",
"6 0.000208809494365\n",
"7 2.95128192228e-05\n",
"8 3.44895318113e-06\n",
"9 6.85237417189e-07\n",
"10 7.61096014459e-08\n",
"11 1.57132110039e-08\n",
"12 1.43155680143e-09\n",
"13 3.49483081912e-10\n",
"14 3.48567470089e-11\n",
"15 7.27357460449e-12\n",
"16 8.38966022033e-13\n",
"17 1.48519413403e-13\n",
"18 2.10786374484e-14\n",
"19 2.82984393717e-15\n"
]
}
],
"source": [
"for n in range(20): #see how little it changes from one iteration to the next\n",
" print n,norm(matrix_power(T,n)-matrix_power(T,n-1))"
]
},
{
"cell_type": "code",
"execution_count": 64,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"step 0 [ 0. 1. 0. 0.]\n",
"step 1 [ 0.17967495 0.35434272 0.26190755 0.20407478]\n",
"step 2 [ 0.21347519 0.3402659 0.26827334 0.17798556]\n",
"step 3 [ 0.21060825 0.34112132 0.27156014 0.17671029]\n",
"step 4 [ 0.20978292 0.34295394 0.27052868 0.17673446]\n",
"step 5 [ 0.20980861 0.34283569 0.27053421 0.17682149]\n"
]
}
],
"source": [
"w=array([0.,1.,0.,0.]) # see the result of n steps starting from 2nd state\n",
"for n in range(6):\n",
" print 'step',n,w\n",
" w = w.dot(T)"
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"array([ 0.19934442, 0.50442549, 0.00408142, 0.29214866])"
]
},
"execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w=rand(4) #eventually doesn't matter where started\n",
"w /= sum(w) #normalize as probability\n",
"w"
]
},
{
"cell_type": "code",
"execution_count": 66,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"step 0 [ 0.19934442 0.50442549 0.00408142 0.29214866]\n",
"step 1 [ 0.25716831 0.24299442 0.31334288 0.18649439]\n",
"step 2 [ 0.21213541 0.34237096 0.27320994 0.17228369]\n",
"step 3 [ 0.20886236 0.3441523 0.27028629 0.17669905]\n",
"step 4 [ 0.20974038 0.34297218 0.27040869 0.17687875]\n",
"step 5 [ 0.2098454 0.34277661 0.27055268 0.17682531]\n"
]
}
],
"source": [
"for n in range(6):\n",
" print 'step',n,w\n",
" w = w.dot(T)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 0
}