Think Stats最初の問題の解答を理解する

開発

さて、前回買ったThink Statsの演習問題1-3の2~4の模範解答を少しずつ理解していきたいと思います。

のっけから見知らぬ文法

if __name__ == '__main__':
    import sys
    main(*sys.argv)

多分ここが一番最初。
まずnameとか’main‘が分からんけど、Pythonではプログラムをファイルに書いたものを「モジュール」というらしく、
このモジュールごとに必ずnameというグローバル変数が付与されるとか。(参考)
xxxって書き方はシステムが定義した名前ってことらしいです。

で、トップレベルで呼び出されたメインモジュールにはこのname属性に’main‘が入るんですね。

で、sys.argvは実行時引数と。(参考

sys.argvの先頭についてる*は何なんだ。
調べてみると可変長引数らしいけど公式ドキュメントのどこに書いてあるのか…
(追記)→ここにありました。

あと、if文で{}使わないのはいいですね。
でも:付け忘れる。

def main(name, data_dir='.'):
    Summarize(data_dir)

mainではSummarizeを呼び出すだけ。
まぁJavaのmainでもインスタンス作ってけるだけだったりしますよね。

ここから本番

def Summarize(data_dir):
    """Prints summary statistics for first babies and others. 第一子とその他に関する簡易統計を出力します。
    
    Returns:
        tuple of Tables 
    """
    table, firsts, others = MakeTables(data_dir)
    ProcessTables(firsts, others)
        
    print 'Number of first babies', firsts.n
    print 'Number of others', others.n

    mu1, mu2 = firsts.mu, others.mu

    print 'Mean gestation in weeks:' 
    print 'First babies', mu1 
    print 'Others', mu2
    
    print 'Difference in days', (mu1 - mu2) * 7.0

で、ここが真のメイン。
MakeTablesでテーブルを取得し、ProcessTablesでそれらを処理していきます。

あれ、ProcessTablesに戻り値がない。
引数をそのまま処理するのはありなんかなぁ…

def MakeTables(data_dir='.'):
    """Reads survey data and returns tables for first babies and others."""
    table = survey.Pregnancies()
    table.ReadRecords(data_dir)

    firsts, others = PartitionRecords(table)
    
    return table, firsts, others

ここでPregnanciesテーブルを読み込み、PartitionRecordsへ。

def PartitionRecords(table):
    """Divides records into two lists: first babies and others.

    Only live births are included

    Args:
        table: pregnancy Table
    """
    firsts = survey.Pregnancies()
    others = survey.Pregnancies()

    for p in table.records:
        # skip non-live births
        if p.outcome != 1:
            continue

        if p.birthord == 1:
            firsts.AddRecord(p)
        else:
            others.AddRecord(p)

    return firsts, others

あり、ここでまたPregnanciesを読み込み直してる。

鵜呑みにしちゃいかん

…あー、分かった。

これ問題2→3→4とプログラムを使いまわしながらやってるから無駄な処理があるんだ。

MakeTablesは元々問題2で使う1つ分のテーブル読み込み関数で、
PartitionRecordsが問題3で使う2つ分のテーブル読み込み関数ですね。

なにげにreturnで変数2つ返しているのが便利。

処理していく

def ProcessTables(*tables):
    """Processes a list of tables
    
    Args:
        tables: gathered argument tuple of Tuples
    """
    for table in tables:
        Process(table)

多分これは2つ分の処理関数。
1つ分の処理関数を呼ぶだけと。

def Process(table):
    """Runs analysis on the given table.
    
    Args:
        table: table object
    """
    table.lengths = [p.prglength for p in table.records]
    table.n = len(table.lengths)
    table.mu = Mean(table.lengths)

こっちは1つ分の処理関数。

ここでまたも分からん文法。

[p.prglength for p in table.records]

ってなんだ。

これも調べてみるとリストの内包表記というものらしい。

ざっくり言うとリストを処理して新しいリストにして返す、みたいな感じ?

今回はtable.recordを1つづつpという名前で取り出して、それのprglengthを新しいリストに加えていく、と。
Javaで書くとこういうこと?

table.length = new List();
for (Data p : table.records) {
    table.length.add(p.prglength);
}

おー、これが1行で記述できるっていうのは素晴らしいですな。

def Mean(t):
    """Computes the mean of a sequence of numbers.

    Args:
        t: sequence of numbers

    Returns:
        float
    """
    return float(sum(t)) / len(t)

で、最後は平均を出す関数と。
sumとlenは組み込み関数ですね。
統計と行っても最初なので何も言うことないですなぁ。

ややこしいのは最初に答えを見たから?

というわけで最初の問題の答えを見ていきましたが、
こんな問題でもPython初心者には躓くことだらけでした。

ただ、問題がプログラムを改修しながら進んでいく形式だったので、
余計にわかりにくくなっていたんだと思います。

あとはこれを見ずに自分で書けるようにしなきゃなぁ…

コメント

タイトルとURLをコピーしました