pandasで分位数・パーセンタイルを取得するquantile
pandasでDataFrame
, Series
の分位数・パーセンタイルを取得するにはquantile()
メソッドを使う。
- pandas.DataFrame.quantile — pandas 2.1.4 documentation
- pandas.Series.quantile — pandas 2.1.4 documentation
分位数・パーセンタイルの定義は以下の通り。
実数(0.0 ~ 1.0)に対し、q 分位数 (q-quantile) は、分布を q : 1 - q に分割する値である。
...
q/100分位数を、q パーセンタイルという。
分位数 - Wikipedia
例えば1/4分位数は25パーセンタイルと同じ。上記Wikipediaのページにも記載されているように、1/4分位数を第1四分位数、3/4分位数を第3四分位数と呼ぶなど、特別な名称を持つ分位数もある。
四分位数を含む要約統計量を算出するメソッドdescribe()
もある。データの概観をつかむためならこちらのほうが便利。
中央値(1/2分位数、50パーセンタイル)だけが必要であればmedian()
でもよい。
- 関連記事: pandasで中央値を取得するmedian
本記事のサンプルコードのpandasのバージョンは以下の通り。バージョンによって仕様が異なる可能性があるので注意。以下のDataFrame
を例とする。
import pandas as pd
print(pd.__version__)
# 2.1.4
df = pd.DataFrame({'col_1': range(11), 'col_2': [i**2 for i in range(11)]})
print(df)
# col_1 col_2
# 0 0 0
# 1 1 1
# 2 2 4
# 3 3 9
# 4 4 16
# 5 5 25
# 6 6 36
# 7 7 49
# 8 8 64
# 9 9 81
# 10 10 100
quantile()の基本的な使い方
デフォルトでは、DataFrame
のquantile()
は各列の中央値(1/2分位数、50パーセンタイル)をSeries
で返す。数値以外の列を含む場合については後述。
print(df.quantile())
# col_1 5.0
# col_2 25.0
# Name: 0.5, dtype: float64
print(type(df.quantile()))
# <class 'pandas.core.series.Series'>
Series
からquantile()
を呼んだ場合は、中央値がスカラー値として返される。
print(df['col_1'].quantile())
# 5.0
print(type(df['col_1'].quantile()))
# <class 'numpy.float64'>
要素の型は元のデータ型および後述の引数interpolation
の設定によって異なる。
取得する分位数・パーセンタイルを指定: 引数q
第一引数q
に取得したい分位・パーセントを0.0
〜1.0
で指定する。
print(df.quantile(0.2))
# col_1 2.0
# col_2 4.0
# Name: 0.2, dtype: float64
リストで複数指定も可能。この場合の返り値はDataFrame
となる。
print(df.quantile([0, 0.25, 0.5, 0.75, 1.0]))
# col_1 col_2
# 0.00 0.0 0.0
# 0.25 2.5 6.5
# 0.50 5.0 25.0
# 0.75 7.5 56.5
# 1.00 10.0 100.0
print(type(df.quantile([0, 0.25, 0.5, 0.75, 1.0])))
# <class 'pandas.core.frame.DataFrame'>
Series
で複数指定すると返り値はSeries
となる。
print(df['col_1'].quantile([0, 0.25, 0.5, 0.75, 1.0]))
# 0.00 0.0
# 0.25 2.5
# 0.50 5.0
# 0.75 7.5
# 1.00 10.0
# Name: col_1, dtype: float64
print(type(df['col_1'].quantile([0, 0.25, 0.5, 0.75, 1.0])))
# <class 'pandas.core.series.Series'>
補間方法を指定: 引数interpolation
値の補間方法は引数interpolation
で指定する。デフォルトは'linear'
で、前後の値から線形補間した値が使われる。
print(df.quantile(0.21))
# col_1 2.1
# col_2 4.5
# Name: 0.21, dtype: float64
print(df.quantile(0.21, interpolation='linear'))
# col_1 2.1
# col_2 4.5
# Name: 0.21, dtype: float64
'lower'
は小さい方、'higher'
は大きい方、'nearest'
は近い方の値が使われる。
print(df.quantile(0.21, interpolation='lower'))
# col_1 2
# col_2 4
# Name: 0.21, dtype: int64
print(df.quantile(0.21, interpolation='higher'))
# col_1 3
# col_2 9
# Name: 0.21, dtype: int64
print(df.quantile(0.21, interpolation='nearest'))
# col_1 2
# col_2 4
# Name: 0.21, dtype: int64
'midpoint'
は前後の値の中間の値(平均値)となる。
print(df.quantile(0.21, interpolation='midpoint'))
# col_1 2.5
# col_2 6.5
# Name: 0.21, dtype: float64
補間方法によるデータ型dtypeの違い
デフォルトは線形補間なので、元のデータ型dtype
が整数int
の場合は浮動小数点数float
に変換される。元の値と等しい値でもデータ型が変わるので注意。
print(df.quantile(0.2))
# col_1 2.0
# col_2 4.0
# Name: 0.2, dtype: float64
'lower'
, 'higher'
, 'nearest'
の場合は元の値がそのまま使われるためデータ型もそのまま。
print(df.quantile(0.2, interpolation='lower'))
# col_1 2
# col_2 4
# Name: 0.2, dtype: int64
行・列を指定: 引数axis
デフォルトは列ごとに処理されるが、引数axis
を1
または'columns'
とすると行ごとの処理となる。
print(df.quantile(axis=1))
# 0 0.0
# 1 1.0
# 2 3.0
# 3 6.0
# 4 10.0
# 5 15.0
# 6 21.0
# 7 28.0
# 8 36.0
# 9 45.0
# 10 55.0
# Name: 0.5, dtype: float64
数値以外も処理するか指定: 引数numeric_only
引数numeric_only
で数値以外の列を処理するか指定できる。numeric_only
をTrue
とすると数値列のみが対象、False
とするとすべての型の列が対象となる。
pandas 2.0からnumeric_only
のデフォルト値がFalse
になった。それより前はTrue
。バージョンによって異なるので注意。
文字列に対するquantile()
文字列の列を加えたDataFrame
を例とする。
df_str = df.copy()
df_str['col_3'] = list('abcdefghijk')
print(df_str)
# col_1 col_2 col_3
# 0 0 0 a
# 1 1 1 b
# 2 2 4 c
# 3 3 9 d
# 4 4 16 e
# 5 5 25 f
# 6 6 36 g
# 7 7 49 h
# 8 8 64 i
# 9 9 81 j
# 10 10 100 k
print(df_str.dtypes)
# col_1 int64
# col_2 int64
# col_3 object
# dtype: object
引数numeric_only
をTrue
とすると数値列のみが対象となり、文字列の列は除外される。
print(df_str.quantile(numeric_only=True))
# col_1 5.0
# col_2 25.0
# Name: 0.5, dtype: float64
引数numeric_only
をFalse
(pandas 2.0からはデフォルト)として文字列の列を対象とする場合、引数interpolation
が'linear'
(デフォルト)や'midpoint'
だとエラーになる。'lower'
, 'higher'
, 'nearest'
だと辞書順に従って前後いずれかの値となる。
# print(df_str.quantile())
# TypeError: unsupported operand type(s) for -: 'str' and 'str'
# print(df_str.quantile(interpolation='midpoint'))
# TypeError: unsupported operand type(s) for -: 'str' and 'str'
print(df_str.quantile([0.2, 0.21, 0.3], interpolation='lower'))
# col_1 col_2 col_3
# 0.20 2 4 c
# 0.21 2 4 c
# 0.30 3 9 d
print(df_str.quantile([0.2, 0.21, 0.3], interpolation='higher'))
# col_1 col_2 col_3
# 0.20 2 4 c
# 0.21 3 9 d
# 0.30 3 9 d
print(df_str.quantile([0.2, 0.21, 0.3], interpolation='nearest'))
# col_1 col_2 col_3
# 0.20 2 4 c
# 0.21 2 4 c
# 0.30 3 9 d
日時datetimeに対するquantile()
日時datetime
の列を加えたDataFrame
を例とする。
df_dt = df.copy()
df_dt['col_3'] = pd.date_range('2023-01-01', '2023-01-11')
print(df_dt)
# col_1 col_2 col_3
# 0 0 0 2023-01-01
# 1 1 1 2023-01-02
# 2 2 4 2023-01-03
# 3 3 9 2023-01-04
# 4 4 16 2023-01-05
# 5 5 25 2023-01-06
# 6 6 36 2023-01-07
# 7 7 49 2023-01-08
# 8 8 64 2023-01-09
# 9 9 81 2023-01-10
# 10 10 100 2023-01-11
print(df_dt.dtypes)
# col_1 int64
# col_2 int64
# col_3 datetime64[ns]
# dtype: object
引数numeric_only
をTrue
とすると数値列のみが対象となり、日時の列は除外される。
print(df_dt.quantile(numeric_only=True))
# col_1 5.0
# col_2 25.0
# Name: 0.5, dtype: float64
日時の列は引数interpolation
が'linear'
(デフォルト)や'midpoint'
でも正しく補間される。もちろん'lower'
, 'higher'
, 'nearest'
でもよい。
print(df_dt.quantile([0.2, 0.21, 0.3]))
# col_1 col_2 col_3
# 0.20 2.0 4.0 2023-01-03 00:00:00
# 0.21 2.1 4.5 2023-01-03 02:24:00
# 0.30 3.0 9.0 2023-01-04 00:00:00
print(df_dt.quantile([0.2, 0.21, 0.3], interpolation='midpoint'))
# col_1 col_2 col_3
# 0.20 2.0 4.0 2023-01-03 00:00:00
# 0.21 2.5 6.5 2023-01-03 12:00:00
# 0.30 3.0 9.0 2023-01-04 00:00:00
print(df_dt.quantile([0.2, 0.21, 0.3], interpolation='lower'))
# col_1 col_2 col_3
# 0.20 2 4 2023-01-03
# 0.21 2 4 2023-01-03
# 0.30 3 9 2023-01-04
print(df_dt.quantile([0.2, 0.21, 0.3], interpolation='higher'))
# col_1 col_2 col_3
# 0.20 2 4 2023-01-03
# 0.21 3 9 2023-01-04
# 0.30 3 9 2023-01-04
print(df_dt.quantile([0.2, 0.21, 0.3], interpolation='nearest'))
# col_1 col_2 col_3
# 0.20 2 4 2023-01-03
# 0.21 2 4 2023-01-03
# 0.30 3 9 2023-01-04
DataFrame
, Series
を時系列データとして処理するための方法は以下の記事を参照。
真偽値boolに対するquantile()
真偽値bool
の列を加えたDataFrame
を例とする。
df_bool = df.copy()
df_bool['col_3'] = [True, False, True, False, True, False, True, False, True, False, True]
print(df_bool)
# col_1 col_2 col_3
# 0 0 0 True
# 1 1 1 False
# 2 2 4 True
# 3 3 9 False
# 4 4 16 True
# 5 5 25 False
# 6 6 36 True
# 7 7 49 False
# 8 8 64 True
# 9 9 81 False
# 10 10 100 True
print(df_bool.dtypes)
# col_1 int64
# col_2 int64
# col_3 bool
# dtype: object
bool
は整数int
のサブクラスで数値扱いなので、引数numeric_only
がTrue
でもFalse
でも処理の対象となるが、pandas 2.1.4時点ではbool
の列があるとエラーになる。
# print(df_bool.quantile())
# TypeError: numpy boolean subtract, the `-` operator, is not supported, use the bitwise_xor, the `^` operator, or the logical_xor function instead.
# print(df_bool.quantile(numeric_only=True))
# TypeError: numpy boolean subtract, the `-` operator, is not supported, use the bitwise_xor, the `^` operator, or the logical_xor function instead.
select_dtypes()
でbool
列を除外するか、astype()
で整数int
に変換すればよい。
print(df_bool.select_dtypes(exclude=bool))
# col_1 col_2
# 0 0 0
# 1 1 1
# 2 2 4
# 3 3 9
# 4 4 16
# 5 5 25
# 6 6 36
# 7 7 49
# 8 8 64
# 9 9 81
# 10 10 100
print(df_bool.select_dtypes(exclude=bool).quantile())
# col_1 5.0
# col_2 25.0
# Name: 0.5, dtype: float64
print(df_bool.astype({'col_3': int}))
# col_1 col_2 col_3
# 0 0 0 1
# 1 1 1 0
# 2 2 4 1
# 3 3 9 0
# 4 4 16 1
# 5 5 25 0
# 6 6 36 1
# 7 7 49 0
# 8 8 64 1
# 9 9 81 0
# 10 10 100 1
print(df_bool.astype({'col_3': int}).quantile())
# col_1 5.0
# col_2 25.0
# col_3 1.0
# Name: 0.5, dtype: float64