概要
Pythonでパーセンタイル値の計算をします。
パーセンタイルの明確な定義無いため実装方法も複数あるようですが、計算方法が違っていても、大量のデータで計算した場合有意な差にはならないとのこと。
今回は下記のサイトを参考に実装しました。また、numpyを用いた方法も紹介します。
http://marketer-thinking.com/statistics/data2.html
実装
def calc_pt(values, pt):
"""
パーセンタイル値を計算する
"""
import math
# 求めるパーセンタイル値がリストの何番目の要素か
order = (len(values) + 1) * (pt / 100)
# 小数部と整数部に分ける
f, i = math.modf(order)
sorted_vals = sorted(values)
# math.modf()はfloatで結果が返るのでキャスト
i = int(i)
return sorted_vals[i-1] + f * (sorted_vals[i-1] - sorted_vals[i])
def calc_pt_numpy(values, pt):
"""
numpyでパーセンタイル値を計算する
"""
import numpy
return numpy.percentile(numpy.array(values), pt)
def main():
"""
メイン処理の実行
"""
import random
for n in [100, 10000, 1000000]:
values = []
for _ in range(n):
values.append(random.uniform(0.0, 100.0))
# パーセンタイル値を計算
for pt in [50, 80, 90, 99]:
my_pt = calc_pt(values, pt)
numpy_pt = calc_pt_numpy(values, pt)
print("n={}, my_pt={}, numpy_pt={}, ratio={}".format(
n, my_pt, numpy_pt, my_pt/numpy_pt
))
print()
if __name__ == '__main__':
main()
実行結果
n=100, my_pt=59.334260375137355, numpy_pt=59.41420584791042, ratio=0.9986544384186888
n=100, my_pt=83.55682075034058, numpy_pt=83.73113216533889, ratio=0.9979182006681324
n=100, my_pt=86.45906782186731, numpy_pt=89.49530919428327, ratio=0.9660737372746022
n=100, my_pt=97.24633378796958, numpy_pt=98.2281366779185, ratio=0.9900048710771318
n=10000, my_pt=49.94757837390801, numpy_pt=49.95727347919067, ratio=0.999805932057387
n=10000, my_pt=80.35364111790138, numpy_pt=80.35485783190325, ratio=0.9999848582396298
n=10000, my_pt=90.1259765722587, numpy_pt=90.15243353511485, ratio=0.9997065307965775
n=10000, my_pt=98.96393575713691, numpy_pt=98.9824941131185, ratio=0.9998125087052223
n=1000000, my_pt=49.985451493835484, numpy_pt=49.98563688434545, ratio=0.9999962911243804
n=1000000, my_pt=80.01341181661982, numpy_pt=80.01344482978872, ratio=0.9999995874047296
n=1000000, my_pt=90.00047774373063, numpy_pt=90.00065066573823, ratio=0.9999980786582505
n=1000000, my_pt=98.99860932658436, numpy_pt=98.99886918947561, ratio=0.999997375092328
numpyで計算したパーセンタイルと一致しませんが、nが大きくなるほど、差異が小さくなっていることがわかります。
疑問
データ数とパーセンタイルによっては、リストのインデックスを超えることになるが、どうすれば良いのか。
例えば、今回の実装ではデータ数が10でパーセンタイルが99を求めることができない。