ThinkStats (7)

棒グラフ二つ描くソレはスルーで。つうかコード配布してる、って先で書いてあるのを発見。そりゃ良いとして演習問題に着手。

演習問題 2-4

書いてる事はよく分からんけど、単純にプログラムする問題ととらえてヤッツケることに。例えば第一子の Pmf は以下なカンジなんですが

>>> pmf.GetDict()
{0: 0.00022660321776569228, 17: 0.00022660321776569228, 
 20: 0.00022660321776569228, 21: 0.00022660321776569228, 
 22: 0.0006798096532970768, 23: 0.00022660321776569228, 
 24: 0.0015862225243598459, 25: 0.00022660321776569228, 
 26: 0.0036256514842510764, 27: 0.00022660321776569228, 
 28: 0.005438477226376614, 29: 0.0020394289598912306, 
 30: 0.016542034896895538, 31: 0.003399048266485384, 
 32: 0.012463176977113076, 33: 0.0063448900974393836, 
 34: 0.006571493315205076, 35: 0.03602991162474507, 
 36: 0.03897575345569907, 37: 0.04713346929526399, 
 38: 0.0616360752322683, 39: 0.47903920235667347, 40: 0.12145932472241106, 
 41: 0.08157715839564922, 42: 0.04645365964196692, 43: 0.01971447994561523, 
 44: 0.005211874008610923, 45: 0.0013596193065941536, 
 46: 0.00022660321776569228, 47: 0.00022660321776569228, 
 48: 0.0006798096532970768}

使用年数が 35 とするとそこまでのナニを削除して再度正規化 (Normalize) というか辞書から Pmf を作れば良いはず。中身を見るに Normalize してますね。

    pmf = Pmf(d, name)
    pmf.Normalize()
    return pmf

ということは算数と言うよりは Python の辞書の扱いな問題、ってことになりますね。つうことは

for k, v in dic.iteritems():

で両方取ってきて、k が使用年数より大きければ k - 使用年数と v を新しい辞書に設定すれば良いのか。以下なカンジ?

def PmfRemainingLifetime(y, pmf):
    newDic = {}
    for k, v in pmf.GetDict().iteritems():
        if y < k:
            newDic[k - y] = v

    return Pmf.MakePmfFromDic(newDic)

本当かなぁ。例えば 5 年で必ず壊れるある機械があって、以下の頻度で壊れてる実績があるとすると

(10 10 10 10 10)

大体 2 割程度の確率で壊れてくって凄い話ですがスルーで。そうか年数を経る毎に死んじゃう確率自体は上がるのかw
最初の PMF は (0.2 0.2 0.2 0.2 0.2) で、3 年経っちゃうと (0.5 0.5) になると。試験を書いてみますね (先に試験から)。

import Pmf
import PmfRemainingLifetime
import unittest

class TestPmfRemainingLifetime(unittest.TestCase):
    def test_PmfRemainingLifetime(self):
        pmf = Pmf.MakePmfFromDict({0: 0.2, 1: 0.2, 2: 0.2, 3: 0.2, 4: 0.2})
        newPmf = PmfRemainingLifetime.PmfRemainingLifetime(2, pmf)
        self.assertEqual([0.5, 0.5], newPmf.Items())

if __name__ == '__main__':
    unittest.main()

で、実行。

$ python PmfRemainingLifetime_test.py 
Traceback (most recent call last):
  File "PmfRemainingLifetime_test.py", line 2, in <module>
    import PmfRemainingLifetime
ImportError: No module named PmfRemainingLifetime

ファイルが無い。touch してみるか。

$ touch PmfRemainingLifetime.py
$ python PmfRemainingLifetime_test.py 
E
======================================================================
ERROR: test_PmfRemainingLifetime (__main__.TestPmfRemainingLifetime)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "PmfRemainingLifetime_test.py", line 8, in test_PmfRemainingLifetime
    newPmf = PmfRemainingLifetime.PmfRemainingLifetime(2, pmf)
AttributeError: 'module' object has no attribute 'PmfRemainingLifetime'

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

メソドが無い。ええと、ここまで書いてようやくまともな FAILED になりました。

import Pmf

def PmfRemainingLifetime(y, pmf):
    return Pmf.Pmf()

出力が以下。

$ python PmfRemainingLifetime_test.py 
F
======================================================================
FAIL: test_PmfRemainingLifetime (__main__.TestPmfRemainingLifetime)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "PmfRemainingLifetime_test.py", line 9, in test_PmfRemainingLifetime
    self.assertEqual([0.5, 0.5], newPmf.Items())
AssertionError: Lists differ: [0.5, 0.5] != []

First list contains 2 additional elements.
First extra element 0:
0.5

- [0.5, 0.5]
+ []

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)

馬鹿なことしてないでさっさと進めますね。盛り込んでみると失敗。

AttributeError: 'module' object has no attribute 'MakePmfFromDic'

MakePmfFromDict でした (汗
で、しかも Items はリストのリストを戻してるなorz
assert を以下に修正して試験パス。

        self.assertEqual([(1, 0.5), (2, 0.5)], newPmf.Items())

なんか gdgd だorz

演習問題 2-5

どんどん進めます。つうかこれ、面白いですね。

(+ (* 1 0.2) (* 0.2 2) (* 0.2 3) (* 0.2 4) (* 0.2 5))
3.0

(/ (+ (* 1 10) (* 2 10) (* 3 10) (* 4 10) (* 5 10)) 50)
3

なのか。むむむ。まず算術平均が以下。

import Pmf

def PmfMean(pmf):
    ret = 0
    for k, v in pmf.GetDict().iteritems():
        ret += k * v

    return ret

試験が以下でパスしてます。

import Pmf
import PmfMean
import unittest

class TestPmfMean(unittest.TestCase):
    def test_PmfMean(self):
        p = Pmf.MakePmfFromDict({1: 0.2, 2: 0.2, 3: 0.2, 4: 0.2, 5: 0.2})
        self.assertEqual(3, PmfMean.PmfMean(p))

if __name__ == '__main__':
    unittest.main()

あ、試験はこう書くのか。

        self.assertEqual(p.Mean(), PmfMean.PmfMean(p))

次、PmfVar は以下かな。

import Pmf

def PmfVar(pmf):
    ret = 0
    mu = pmf.Mean()
    for k, v in pmf.GetDict().iteritems():
        ret += ((k - mu) ** 2) * v

    return ret

試験書くのが楽でいいですね。

import Pmf
import PmfVar
import unittest

class TestPmfVar(unittest.TestCase):
    def test_PmfVar(self):
        p = Pmf.MakePmfFromDict({1: 0.2, 2: 0.2, 3: 0.2, 4: 0.2, 5: 0.2})
        self.assertEqual(p.Var(), PmfVar.PmfVar(p))

if __name__ == '__main__':
    unittest.main()

2 章残りに目を通す方向。あ、電話しなきゃ、なんだった。続きがあればこのまま追記の方向です。

演習問題 2-6

中身はスルー。月曜朝とかで確認の方向。Python の辞書ってキーが数値ならその順で取り出せるのかな。それ前提でいくと話は早い。
以下をでっちあげて

import Pmf

def ProbCommon(f, t, p):
    ret = 0
    for k, v in p.GetDict().iteritems():
        if (f <= k) and (k <= t):
           ret += v

    return ret

def ProbEarly(p):
    return ProbCommon(0, 37, p)

def ProbOnTime(p):
    return ProbCommon(38, 40, p)

def ProbLate(p):
    return ProbCommon(41, 99, p)

REPL で確認。

>>> import Pmf
>>> import thinkstats
>>> import survey
>>> table = survey.Pregnancies()
>>> table.ReadRecords()
>>> first_p = []
>>> other_p = []
>>> 
>>> for i in table.records:
...     if i.outcome == 1:
...         if i.birthord == 1:
...             first_p.append(i.prglength)
...         else:
...             other_p.append(i.prglength)
... 
>>> first_pmf = Pmf.MakePmfFromList(first_p)
>>> other_pmf = Pmf.MakePmfFromList(other_p)
>>> first_pmf
<Pmf.Pmf object at 0x7fb605bcaf90>
>>> import risk
>>> risk.ProbEarly(first_pmf)
0.18241559030138227
>>> risk.ProbEarly(other_pmf)
0.16832101372756073

あとは正解コードを確認することにして先に進もう。