より良いエンジニアを目指して

1日1つ。良くなる!上手くなる!

quantile(分位数)を学び、箱ひげ図について理解を深める。

Kaggleで他の方のKernelを見ていたら、numpyのquantile関数を使っているのを見かけました。

numpyでは1.15から使える関数なのです。

numpy.quantile

quantileどころか分位数自体、知りませんでした。

分位数とは、結論から言えば、Wikipediaにある

分布をq:1-q に分割する値である。

というのが端的に表しています。

分位数 - Wikipedia

ですが、しっくり来なかったので、Pythonのコードを書きながら、理解を深めて行きました。

import pandas as pd
import numpy as np

df = np.array([1,4,9,16,25])

print('quantile(0.5) =' ,np.quantile(df,0.5)) # 9
print('quantile(0.25) =' ,np.quantile(df,0.25)) # 4
print('quantile(0.75) =' ,np.quantile(df,0.75)) # 16

quantile(0.5)にした場合は中央値となる9が取得されます。 9を境にして、[1,4],[16,25]という0.5:0.5=2:2に集合を分けられます。

同様にquantile(0.25)とquantile(0.75)の場合も1:3ないし、3:1に集合を分割できる値となります。

上記は説明しやすいように都合の良い集合にしていますが、では [1,4,9,16]のように二つに分けられない場合はどうでしょうか。

import pandas as pd
import numpy as np

df = np.array([1,4,9,16])

print('quantile(25) =' ,np.quantile(df,0.25)) # 3.25
print('quantile(50) =' ,np.quantile(df,0.5)) # 6.5
print('quantile(75) =' ,np.quantile(df,0.75)) # 10.75

この場合は、中央値は(4+9) / 2 = 6.5となります。

(4-1) * 0.25 = 0.75より1 * 0.25 + 4 * 0.75 = 3.25

(4-1) * 0.75 = 2.25より9 * 0.75 + 16 * 0.25 = 10.75

となります。

quantileを自分で実装してみる

こんな感じでしょうか。

import math
def my_quantile(array,q):
    array.sort()
    index = (len(array) - 1) * q
    low = math.floor(index)
    high = math.ceil(index)
    return array[low] * (1 - (index-low)) + array[high] * (index-low)

f:id:rimever:20190320200222p:plain

※配列のソートが必要だと気づいたので追記しました。

箱ひげ図

このquantileは箱ひげ図を正しく理解する上で重要です。

箱ひげ図の箱の部分は下が1/4分位数[quantile(0.25)]であり、上が3/4分位数[quantile(0.75)]となり、中央の線は1/2分位数(中央値)となっています。

この箱は値全体の上位25%〜75%を表しているのです。

中央の線は平均ではありません。

f:id:rimever:20190319224258p:plain
中央の線は平均ではありません。中央値です。

ひげの上と下は最大と最小です。

パーセンタイル

分位数を%に置き換えたものです。0.25分位数であれば25パーセンタイルです。これもnumpyの関数として存在します。

import pandas as pd
import numpy as np

df = np.array([1,4,9,16,25,36,49,64,81])

print('percentile(25) =' ,np.percentile(df,25))
print('percentile(50) =' ,np.percentile(df,50))
print('percentile(100) =' ,np.percentile(df,100))

DataFrameにもquantileはある

import pandas as pd
import numpy as np

df = pd.DataFrame(np.array([1,4,9,16,25,36,49,64,81]),
                                    columns=['number'])

print(df['number'].quantile(0.25))