ひるあんどんブログ

色々なことに手を出してみるブログ

Median

メジアン(中央値)は整列した配列の上位半分と下位半分を分離する数値です。 配列に奇数個の数があるときはメジアンは配列の中央の値です。 配列に偶数個の数があるときは、中央の値は一つではないので、代わりに中央の二つの値の平均になります. このミッションでは自然数の空でない配列(X)が与えられて、上位半分と下位半分を分離してメジアンを見つけます。

入力: 配列、整数のリスト

出力: メジアン浮動小数点または整数

例:

checkio([1, 2, 3, 4, 5]) == 3

checkio([3, 1, 2, 5, 3]) == 3

checkio([1, 300, 2, 200, 1]) == 2

checkio([3, 6, 20, 99, 10, 15]) == 12.5



使用法: メジアンは統計と確率の理論のために使われます。特に偏った分布のための重要な値です。 例えば、データの集合から人々の富の平均を知りたいとします。100人は月に$100を稼ぎ 10人は$1,000,000を稼ぎます。平均を取ると$91,000ということになります。 でもこれは実体を表していないので良い値ではありません。 この場合メジアンは有用な値を与えて実体を反映するでしょう。 Wikipediaの記事. (訳注 日本語版)

事前条件:
1 < len(data) ≤ 1000
all(0 ≤ x < 10 ** 6 for x in data)

def checkio(data):
    data.sort()
    length = len(data)
    mid = length % 2
    if mid == 0:
        result = round(length/2)
        find = (data[result] + data[result-1]) / 2
        return find
    result = length // 2
    return data[result]
    

#These "asserts" using only for self-checking and not necessary for auto-testing
if __name__ == '__main__':
    assert checkio([1, 2, 3, 4, 5]) == 3, "Sorted list"
    assert checkio([3, 1, 2, 5, 3]) == 3, "Not sorted list"
    assert checkio([1, 300, 2, 200, 1]) == 2, "It's not an average"
    assert checkio([3, 6, 20, 99, 10, 15]) == 12.5, "Even length"
    print("Start the long test")
    assert checkio(list(range(1000000))) == 499999.5, "Long."
    print("The local tests are done.")

これはroundという関数を知らなかったので苦労した。

roundとはリファレンスによると

round(number[, ndigits])¶(原文)

    number を小数点以下 ndigits 桁に丸めた浮動小数点数の値を返します。 ndigits が省略されると、デフォルトの 0 が使われます。 number.__round__(ndigits) に委譲します。

    round() をサポートする組み込み型では、値は 10 のマイナス ndigits 乗の倍数の中で最も近いものに丸められます; 二つの倍数が同じだけ近いなら、偶数を選ぶ方に (ですから例えば、 round(0.5) と round(-0.5) は両方とも 0 に、 round(1.5) は 2 に) 丸められます。返り値は 1 引数で呼ばれたなら整数、そうでなければ number と同じ型です。 

    注釈

    浮動小数点数に対する round() の振る舞いは意外なものかもしれません: 例えば、 round(2.675, 2) は予想通りの 2.68 ではなく 2.67 を与えます。これはバグではありません: これはほとんどの小数が浮動小数点数で正確に表せないことの結果です。詳しくは 浮動小数点演算、その問題と制限 を参照してください。

なので、今回だと四捨五入しているだけ。
リストの長さが偶数ならば、中央値となる値は2つあるので、。ってちょっとまてよ。これはroundの意味がないぞ…。そもそも偶数なんだから2で割り切れるはずだ。あれ、なんでこうやって書いたんだっけ…。


あ、そうだ。python3は整数の除算が独特なんだった。

4 / 2 => 2.0

になる。答えがfloat型でかえってくるから、これがエラー出してしまったんだった。思い出した。
だからroundで丸めようとしたんだ。

でも // 使えば、小数点以下はなくなって、ひと桁だけが帰るからこれ使ったほうが素直だ。

4 // 2 => 2

3 // 2 => 1 でも、 round(3/2) => 2 だからこれは注意しないと…。


だから、

def checkio(data):
    data.sort()
    length = len(data)
    mid = length % 2

    if mid == 0:
        result = length // 2
        find = (data[result] + data[result-1]) / 2
        return find
    result = length // 2
    return data[result]
    

#These "asserts" using only for self-checking and not necessary for auto-testing
if __name__ == '__main__':
    assert checkio([1, 2, 3, 4, 5]) == 3, "Sorted list"
    assert checkio([3, 1, 2, 5, 3]) == 3, "Not sorted list"
    assert checkio([1, 300, 2, 200, 1]) == 2, "It's not an average"
    assert checkio([3, 6, 20, 99, 10, 15]) == 12.5, "Even length"
    print("Start the long test")
    assert checkio(list(range(1000000))) == 499999.5, "Long."
    print("The local tests are done.")