Numpy percentile で理解するデータの分布

はい、承知いたしました。NumPyのpercentile関数を用いてデータの分布を理解するための詳細な記事を約5000語で記述します。


NumPy percentile で理解するデータの分布:統計的洞察を得るための強力なツール

はじめに:データ分析における分布理解の重要性

データ分析の旅を始めるとき、まず最初に行うべき最も重要なステップの一つは、データの「分布」を理解することです。データがどのように散らばっているか、どのような値が頻繁に出現するか、極端な値は存在するかなどを把握することは、その後の分析、モデリング、意思決定の基盤となります。

例えば、ある商品の販売データがあるとします。単に合計売上を見るだけでは、特定の時期に集中して売れているのか、それとも年間を通じて均等に売れているのか、高額商品がたまに売れることで売上が押し上げられているのか、低価格商品が大量に売れているのかといった、売上の「パターン」や「傾向」は見えてきません。データの分布を調べることで、これらの詳細な情報を掴むことができます。

データの分布を理解するためには、様々な統計的な指標や手法が用いられます。平均値や中央値といった中心傾向を示す指標、標準偏差や分散といったばらつきを示す指標、そしてヒストグラムのような視覚化手法などが一般的です。

本記事では、これらのツールの強力な補完となり、データの位置や相対的な順位を理解する上で非常に有用な概念である「パーセンタイル(Percentile)」に焦点を当てます。そして、Pythonのデータ分析ライブラリとして広く使われているNumPyが提供するpercentile関数を使い、どのようにデータの分布を深く理解できるかを詳細に解説します。

NumPyのpercentile関数は非常に柔軟であり、データの次元や欠損値の扱い、そして計算方法(補間方法)の選択肢など、多くのオプションを提供しています。これらのオプションを理解することで、より正確で目的に合ったパーセンタイル計算を行うことができます。

この記事では、パーセンタイルの基本的な概念から始め、np.percentile関数の基本的な使い方、多次元配列での利用法、そして特に重要な「補間方法」の詳細な解説を行います。さらに、パーセンタイルを用いた四分位数やIQRの計算、外れ値の特定、データの比較といった実践的な応用例を紹介し、データの分布理解にどのように役立つかを具体的に示します。約5000語というボリュームで、これらのトピックを網羅し、NumPyのpercentileを使いこなすための知識を習得していただくことを目指します。

1. データの分布とは何か? なぜ理解する必要があるのか?

1.1. 分布の基本概念

データの「分布(Distribution)」とは、データセット内の個々の値がどのように散らばっているか、あるいは出現するかのパターンを指します。言い換えれば、データポイントが数値範囲内のどこに位置し、どの程度密集しているか、または離れているかを示します。

例えば、学生のテストの点数のデータセットがあるとします。
* 分布が狭い:多くの学生の点数が平均点の近くに集中している。
* 分布が広い:点数が低い学生から高い学生まで幅広く散らばっている。
* 分布が右に歪んでいる:多くの学生が高得点を取っているが、一部に低得点の学生がいる(左に裾野が伸びる)。
* 分布が左に歪んでいる:多くの学生が低得点を取っているが、一部に高得点の学生がいる(右に裾野が伸びる)。
* 分布に複数の山がある:例えば、クラスが二つに分かれており、それぞれのクラスの平均点が大きく異なる場合など。

1.2. 分布を理解する目的

データの分布を理解することは、データ分析の様々な段階で不可欠です。

  1. データの要約と把握: データセット全体の傾向や特徴を素早く掴むことができます。平均値だけでは見えない、データの「形」が見えてきます。
  2. 異常値(外れ値)の特定: 分布の端に位置するデータポイントは、入力エラー、測定ミス、あるいは分析上重要な特異なイベントである可能性があります。分布を視覚化したり、統計量を見たりすることで、これら異常値を特定しやすくなります。
  3. 統計モデルの選択: 多くの統計モデルや機械学習アルゴリズムは、データの分布について特定の仮定を置きます(例: 正規分布を仮定するT検定や線形回帰)。データの実際の分布を調べることで、適切なモデルを選択したり、データを前処理して仮定を満たすように変換したりする必要があるかを判断できます。
  4. 意思決定: データの分布に基づいた分析結果は、より情報に基づいた意思決定を可能にします。例えば、商品の価格設定、在庫管理、マーケティング戦略などは、顧客の購買金額の分布や利用頻度の分布を理解することで最適化できます。
  5. データ間の比較: 複数のデータセットがある場合、それぞれの分布を比較することで、データ間の類似点や相違点を明らかにできます。

1.3. 分布を示す基本的な統計量

分布を数値的に要約するための基本的な統計量には以下のようなものがあります。

  • 中心傾向 (Measures of Central Tendency):
    • 平均値 (Mean): 全ての値を合計し、データ数で割った値。データの「バランスポイント」。外れ値に影響されやすい。
    • 中央値 (Median): データを小さい順に並べたときの中央の値。データ数が偶数の場合は中央の2つの値の平均。外れ値に強いロバストな指標。
    • 最頻値 (Mode): データセットの中で最も頻繁に出現する値。カテゴリーデータにも使える。
  • ばらつき (Measures of Variability or Dispersion):
    • 範囲 (Range): 最大値から最小値を引いた値。非常に単純だが、外れ値に大きく影響される。
    • 分散 (Variance): 各データポイントが平均値からどれだけ離れているか(偏差)の二乗の平均。ばらつきの度合いを示す。単位が元のデータの二乗になる。
    • 標準偏差 (Standard Deviation): 分散の正の平方根。元のデータと同じ単位になるため、解釈しやすい。平均値からの典型的なばらつきの大きさを示す。外れ値に影響されやすい。
    • 四分位範囲 (Interquartile Range – IQR): データを四等分したときの、第3四分位数と第1四分位数との差。データの中心50%のばらつきを示す。外れ値に強いロバストな指標。
  • 形状 (Measures of Shape):
    • 歪度 (Skewness): 分布の非対称性を示す指標。左右どちらに裾野が長いか。
    • 尖度 (Kurtosis): 分布の山の尖り具合と裾野の重みを示す指標。正規分布と比べて、データが中央に集中しているか、あるいは極端な値が多いか。

これらの統計量に加え、パーセンタイルはデータの相対的な位置を理解するための重要なツールとなります。

2. パーセンタイルとは?

2.1. パーセンタイルの定義

kパーセンタイル(k-th percentile)とは、データを小さい順に並べたときに、全体のデータのうちk%がその値以下になるような値を指します。

例えば、あるテストであなたの点数が80点だったとし、この80点が全体の90パーセンタイルだったとします。これは、テストを受けた学生全体の90%の学生が80点以下の点数であったことを意味します。逆に言えば、あなたの点数よりも高い点数を取った学生は全体の10%に過ぎないということになります。

パーセンタイルは、データの絶対値だけでなく、そのデータが全体の中でどのような位置にあるのか、相対的な順位を知るのに役立ちます。

2.2. パーセンタイルの直感的な理解

パーセンタイルを直感的に理解するためには、データを直線上に並べて考えるのが最も分かりやすいです。

データセット {5, 10, 15, 20, 25} があるとします。
データを昇順に並べると: 5, 10, 15, 20, 25

  • 0パーセンタイル: データの最小値。この例では 5。
  • 25パーセンタイル: データの25%がこの値以下になる値。この例では 10。データ5は20%(1/5)、データ10まで含めると40%(2/5)がこの値以下になります。パーセンタイルの計算には補間が必要になることが多く、NumPyのデフォルト計算では10が25パーセンタイルに近い値として得られます(後述の補間方法で詳細に解説)。
  • 50パーセンタイル: データの50%がこの値以下になる値。これは中央値 (Median) に他なりません。この例では 15。
  • 75パーセンタイル: データの75%がこの値以下になる値。この例では 20。
  • 100パーセンタイル: データの最大値。この例では 25。

このように、パーセンタイルはデータを0%から100%までの範囲で区切り、特定の位置に対応する値を示します。

2.3. なぜパーセンタイルが有用なのか?

  1. データの相対的な位置を把握: 個々のデータポイントが、データセット全体の中でどれだけ「高い」または「低い」位置にあるかを理解できます。絶対値だけでは比較しにくい異なる尺度や分布を持つデータ間での比較にも役立ちます。
  2. 外れ値へのロバスト性: 平均値や標準偏差は外れ値に大きく影響されますが、パーセンタイル(特に中央値や四分位数)は、データセットのごく一部の値が変わっても大きく変動しないため、外れ値に強い(ロバストな)指標です。
  3. 分布の形状把握: いくつかのパーセンタイル(特に四分位数)を組み合わせることで、データのばらつきや歪度についての手がかりを得られます。
  4. 基準値の設定: パフォーマンス評価(例: 学生の学力、選手の能力)、健康指標(例: 成長曲線)、リスク評価などにおいて、パーセンタイルは基準値や閾値を設定するためによく使われます。

2.4. 四分位数 (Quartiles)

パーセンタイルの特別なケースとして、四分位数があります。これはデータを四等分する値です。

  • 第1四分位数 (Q1): 25パーセンタイル。データの最小値から中央値までのちょうど中央に位置する値。データの下位25%がこの値以下になります。
  • 第2四分位数 (Q2): 50パーセンタイル。データの中央値 (Median) です。データの下位50%がこの値以下になります。
  • 第3四分位数 (Q3): 75パーセンタイル。データの中央値から最大値までのちょうど中央に位置する値。データの下位75%がこの値以下になります。

これらの四分位数を使うことで、データの中心50%がどの範囲に収まっているかを示す四分位範囲(IQR = Q3 – Q1)を計算できます。IQRはばらつきのロバストな指標です。

3. NumPyとデータの数値計算

Pythonで数値計算や配列操作を行う際に最も広く使われているライブラリがNumPy (Numerical Python) です。NumPyは、多次元配列オブジェクト(ndarray)と、その配列を操作するための高速な関数群を提供します。

大規模なデータセットに対する統計計算や数学的演算を効率的に行うために設計されており、Python標準のリストを使うよりもはるかに高速です。データ分析、科学計算、機械学習など、Pythonを用いた多くの分野で基盤となっています。

NumPyには、平均値 (np.mean), 中央値 (np.median), 標準偏差 (np.std), 最大値 (np.max), 最小値 (np.min) など、様々な基本的な統計量を計算するための関数が組み込まれています。そして、本記事の主題であるパーセンタイルを計算するためのnp.percentile関数も提供されています。

np.percentileは、NumPy配列やPythonリストなどの配列ライクなデータを受け取り、指定されたパーセンタイルに対応する値を返します。その実装は効率的であり、大規模データに対しても実用的な速度で計算を行うことができます。

4. NumPyのpercentile関数を使ってみる

NumPyのpercentile関数は、配列データに対して指定したパーセンタイルの値を計算します。基本的な使い方は非常にシンプルです。

“`python
import numpy as np

サンプルデータを作成

data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
“`

4.1. 基本的な使い方:単一のパーセンタイル値を計算

np.percentile(a, q) の形式で使います。
a: パーセンタイルを計算したい配列または配列ライクなオブジェクト。
q: 計算したいパーセンタイルの値(0から100までの数値)。

“`python

50パーセンタイル(中央値)を計算

median_value = np.percentile(data, 50)
print(f”データ: {data}”)
print(f”50パーセンタイル (中央値): {median_value}”)

出力例: 50パーセンタイル (中央値): 5.5

“`

なぜ5.5になるのでしょうか? データは10個あります。小さい順に並べると 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 です。中央値(50パーセンタイル)は、データを2等分する値です。データ数が偶数の場合、中央の2つの値(5と6)の平均になります。NumPyのpercentile関数(デフォルトの補間方法)は、このように計算します。

“`python

25パーセンタイルを計算

q1_value = np.percentile(data, 25)
print(f”25パーセンタイル (Q1): {q1_value}”)

出力例: 25パーセンタイル (Q1): 3.25

75パーセンタイルを計算

q3_value = np.percentile(data, 75)
print(f”75パーセンタイル (Q3): {q3_value}”)

出力例: 75パーセンタイル (Q3): 7.75

“`

これらの値(3.25, 5.5, 7.75)は、データセット {1, 2, …, 10} において、それぞれ全体の約25%, 50%, 75%のデータがその値以下になるような位置を示しています。なぜこれらの特定の値になるのかは、後述する補間方法のセクションで詳しく解説します。

4.2. 複数のパーセンタイル値を一度に計算

q にはパーセンタイルの値のリストやNumPy配列を渡すこともできます。この場合、指定したすべてのパーセンタイルに対応する値がNumPy配列として返されます。

“`python

25, 50, 75パーセンタイルを一度に計算

percentiles_q1_q2_q3 = np.percentile(data, [25, 50, 75])
print(f”[25, 50, 75]パーセンタイル: {percentiles_q1_q2_q3}”)

出力例: [25, 50, 75]パーセンタイル: [3.25 5.5 7.75]

0から100まで、10刻みのパーセンタイルを計算

percentiles_0_to_100 = np.percentile(data, np.arange(0, 101, 10))
print(f”0から100までの10刻みパーセンタイル: {percentiles_0_to_100}”)

出力例: 0から100までの10刻みパーセンタイル: [ 1. 2. 3. 4.25 5.5 6.75 8. 9. 10. 10. 10. ]

“`

この機能は、データの分布を大まかに把握するために、複数のパーセンタイル(例えば10パーセンタイル刻み)を一度に計算したい場合に非常に便利です。

5. axisパラメータによる多次元配列の処理

np.percentile関数は、1次元配列だけでなく、多次元NumPy配列に対してもパーセンタイルを計算できます。どの軸(次元)に沿って計算を行うかを指定するために axis パラメータを使用します。

axisを省略した場合、または axis=None とした場合、配列はフラット化(1次元配列に変換)されてからパーセンタイルが計算されます。これは、多次元配列全体のパーセンタイルを知りたい場合に便利です。

“`python

2×5の2次元配列を作成

data_2d = np.array([[10, 20, 30, 40, 50],
[15, 25, 35, 45, 55]])

print(f”元の2次元配列:\n{data_2d}”)

配列全体をフラット化して50パーセンタイルを計算

median_flat = np.percentile(data_2d, 50)
print(f”\n配列全体の50パーセンタイル (フラット化): {median_flat}”)

出力例: 配列全体の50パーセンタイル (フラット化): 32.5

(全要素 [10,15,20,25,30,35,40,45,50,55] の中央値は (30+35)/2 = 32.5)

“`

5.1. axis=0:列ごとの計算

axis=0 を指定すると、各列(行に沿って)のパーセンタイルが計算されます。結果として返される配列は、元の配列の列数と同じ長さの1次元配列になります。

“`python

各列の50パーセンタイルを計算 (axis=0)

median_per_column = np.percentile(data_2d, 50, axis=0)
print(f”\n各列の50パーセンタイル (axis=0): {median_per_column}”)

出力例: 各列の50パーセンタイル (axis=0): [12.5 22.5 32.5 42.5 52.5]

(列0: [10, 15] -> 12.5, 列1: [20, 25] -> 22.5, … 列4: [50, 55] -> 52.5)

“`

5.2. axis=1:行ごとの計算

axis=1 を指定すると、各行(列に沿って)のパーセンタイルが計算されます。結果として返される配列は、元の配列の行数と同じ長さの1次元配列になります。

“`python

各行の50パーセンタイルを計算 (axis=1)

median_per_row = np.percentile(data_2d, 50, axis=1)
print(f”\n各行の50パーセンタイル (axis=1): {median_per_row}”)

出力例: 各行の50パーセンタイル (axis=1): [30. 40.]

(行0: [10, 20, 30, 40, 50] -> 30, 行1: [15, 25, 35, 45, 55] -> 40)

“`

5.3. 複数軸の指定

NumPyのバージョンによっては、axisにタプルを指定して複数の軸に沿った計算を一度に行うことも可能です(結果は指定された軸が縮約された次元の配列になります)。

“`python

例: 3D配列で特定の2軸に沿ってパーセンタイルを計算

data_3d = np.arange(234).reshape(2, 3, 4)
print(f”\n元の3次元配列:\n{data_3d}”)

軸0と軸2に沿って50パーセンタイルを計算

元の shape (2, 3, 4) -> 軸0と軸2が縮約 -> 結果の shape (3,)

median_axis_0_2 = np.percentile(data_3d, 50, axis=(0, 2))
print(f”\n軸0と軸2に沿った50パーセンタイル (axis=(0, 2)): {median_axis_0_2}”)

出力例: 軸0と軸2に沿った50パーセンタイル (axis=(0, 2)): [11.5 13.5 15.5]

(例: 1つ目の要素 11.5 は、元の配列で軸0と軸2に渡る要素の集合

[[ 0, 1, 2, 3], [12, 13, 14, 15]] をフラット化した [0,1,2,3,12,13,14,15] の中央値)

“`

axisパラメータを理解することで、テーブルデータ(列ごとに変数、行ごとに行や観測値)のような多次元データセットから、特定の変数や特定のグループに対するパーセンタイルを効率的に計算することができます。

6. 補間方法(interpolation)の詳細

パーセンタイルの計算において、指定されたパーセンタイルに対応する「位置」が、データセットを小さい順に並べたときに存在するデータポイントの間に来る場合があります。例えば、10個のデータがある場合、データポイントの位置は1番目、2番目、…、10番目と整数で決まります。しかし、25パーセンタイルを計算する場合、計算上の位置は (N-1) * (p/100) + 1 のような式に基づき、整数にならないことがあります(Nはデータ数、pはパーセンタイル)。

このような場合に、そのパーセンタイル値として具体的にどの値を採用するかを決めるのが「補間方法(interpolation)」です。NumPyのpercentile関数は、interpolationパラメータを使ってこの方法を指定できます。デフォルトは 'linear' ですが、他にも選択肢があり、結果が異なる場合があります。

以下のデータセットを使って、それぞれの補間方法の違いを見ていきましょう。
データセット: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} (サイズ N=10)

例として、25パーセンタイル (p=25) を計算することを考えます。
パーセンタイル位置の計算式の一例として、 index = (N - 1) * (p / 100) を使うことがあります。このインデックスは0から始まるインデックスに対応します。
index = (10 - 1) * (25 / 100) = 9 * 0.25 = 2.25
これは、ソートされた配列のインデックス2 (data[2] -> 3) とインデックス3 (data[3] -> 4) の間に2.25の位置があることを意味します。

NumPyのドキュメントによると、linear補間の位置計算は (N - 1) * p / 100 です。この値が整数でない場合、その前後のインデックスにある値を使って補間します。
インデックス 2.25 は、インデックス 2 (値 3) とインデックス 3 (値 4) の間にあります。

6.1. 'linear' (線形補間 – デフォルト)

指定されたパーセンタイルの位置がデータポイント間にある場合、その前後のデータポイントの値を線形に補間して値を決定します。最も一般的で標準的な方法です。

位置 ii+1 の間にある場合、data[i]data[i+1] の値を使って data[i] + (data[i+1] - data[i]) * (fractional_part) のように計算します。fractional_partは index の小数点以下の部分です。

例: N=10, p=25, index=2.25
data[2] は 3, data[3] は 4。小数点以下の部分 0.25
補間値 = data[2] + (data[3] - data[2]) * 0.25
補間値 = 3 + (4 - 3) * 0.25 = 3 + 1 * 0.25 = 3.25

“`python
data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
p = 25
linear_percentile = np.percentile(data, p, interpolation=’linear’)
print(f”データ: {data}”)
print(f”{p}パーセンタイル (‘linear’): {linear_percentile}”)

出力: 25パーセンタイル (‘linear’): 3.25

p = 50
linear_percentile_50 = np.percentile(data, p, interpolation=’linear’)
print(f”50パーセンタイル (‘linear’): {linear_percentile_50}”)

出力: 50パーセンタイル (‘linear’): 5.5

(index = (10-1)0.5 = 4.5. data[4]=5, data[5]=6. 5 + (6-5)0.5 = 5.5)

“`

6.2. 'lower' (下限値)

指定されたパーセンタイルの位置がデータポイント間にある場合、その位置よりも小さいインデックスにあるデータポイントの値(つまり、左側の値)を採用します。

例: N=10, p=25, index=2.25
インデックス 2.25 はインデックス 2 と 3 の間にあります。位置よりも小さいインデックスは 2 です。
採用値 = data[2] = 3

“`python
p = 25
lower_percentile = np.percentile(data, p, interpolation=’lower’)
print(f”{p}パーセンタイル (‘lower’): {lower_percentile}”)

出力: 25パーセンタイル (‘lower’): 3

p = 50
lower_percentile_50 = np.percentile(data, p, interpolation=’lower’)
print(f”50パーセンタイル (‘lower’): {lower_percentile_50}”)

出力: 50パー센タイル (‘lower’): 5

(index=4.5. 位置よりも小さいインデックスは 4. data[4]=5)

“`

6.3. 'higher' (上限値)

指定されたパーセンタイルの位置がデータポイント間にある場合、その位置よりも大きいインデックスにあるデータポイントの値(つまり、右側の値)を採用します。

例: N=10, p=25, index=2.25
インデックス 2.25 はインデックス 2 と 3 の間にあります。位置よりも大きいインデックスは 3 です。
採用値 = data[3] = 4

“`python
p = 25
higher_percentile = np.percentile(data, p, interpolation=’higher’)
print(f”{p}パーセンタイル (‘higher’): {higher_percentile}”)

出力: 25パーセンタイル (‘higher’): 4

p = 50
higher_percentile_50 = np.percentile(data, p, interpolation=’higher’)
print(f”50パーセンタイル (‘higher’): {higher_percentile_50}”)

出力: 50パーセンタイル (‘higher’): 6

(index=4.5. 位置よりも大きいインデックスは 5. data[5]=6)

“`

6.4. 'nearest' (最近傍値)

指定されたパーセンタイルの位置に最も近いインデックスにあるデータポイントの値を採用します。同距離の場合は、NumPyのドキュメントによると'lower'と同じく下限側の値(小さい方のインデックス)を採用します。

例: N=10, p=25, index=2.25
インデックス 2.25 はインデックス 2 (距離 0.25) と 3 (距離 0.75) の間にあります。最も近いインデックスは 2 です。
採用値 = data[2] = 3

“`python
p = 25
nearest_percentile = np.percentile(data, p, interpolation=’nearest’)
print(f”{p}パーセンタイル (‘nearest’): {nearest_percentile}”)

出力: 25パーセンタイル (‘nearest’): 3

p = 50
nearest_percentile_50 = np.percentile(data, p, interpolation=’nearest’)
print(f”50パーセンタイル (‘nearest’): {nearest_percentile_50}”)

出力: 50パーセンタイル (‘nearest’): 5

(index=4.5. インデックス 4と5から同距離. lower側のインデックス 4 を採用. data[4]=5)

“`

6.5. 'midpoint' (中間値)

指定されたパーセンタイルの位置がデータポイント間にある場合、その前後のデータポイントの値を平均して採用します。これは 'linear' 補間において、位置がちょうど中央 (fractional_part = 0.5) に来た場合と同じです。

例: N=10, p=25, index=2.25
インデックス 2.25 はインデックス 2 と 3 の間にあります。これらの値の平均は (data[2] + data[3]) / 2 となります。
採用値 = (3 + 4) / 2 = 3.5

“`python
p = 25
midpoint_percentile = np.percentile(data, p, interpolation=’midpoint’)
print(f”{p}パーセンタイル (‘midpoint’): {midpoint_percentile}”)

出力: 25パーセンタイル (‘midpoint’): 3.5

p = 50
midpoint_percentile_50 = np.percentile(data, p, interpolation=’midpoint’)
print(f”50パーセンタイル (‘midpoint’): {midpoint_percentile_50}”)

出力: 50パーセンタイル (‘midpoint’): 5.5

(index=4.5. data[4]=5, data[5]=6. (5+6)/2=5.5)

“`

6.6. 補間方法の選択について

どの補間方法を選択すべきかは、データの性質や分析の目的に依存します。

  • 'linear': 最も一般的で、連続的なデータを扱っているという仮定に立つ場合に適しています。多くの統計ソフトウェアのデフォルトもこれに近いです。
  • 'lower', 'higher', 'nearest': データが離散的な値を取る場合や、実際のデータポイントの中から値を選びたい場合に検討されます。例えば、アンケートの選択肢(1, 2, 3, 4, 5)のようなデータの場合、補間された小数値よりも、実際に存在する選択肢の値の方が解釈しやすいかもしれません。
  • 'midpoint': 'linear'でちょうど中間になる場合と同じ結果になりますが、計算方法として平均を採用することが明確な場合に使うことがあります。

ほとんどの場合、デフォルトの'linear'で問題ありませんが、特にデータ数が少ない場合や、パーセンタイルがデータポイント間に位置する場合に、補間方法によって結果が大きく変わる可能性があることを理解しておくことが重要です。異なるソフトウェアやライブラリで計算したパーセンタイル値が微妙に異なる場合、この補間方法の違いが原因であることがよくあります。

NumPy 1.22以降では、interpolationパラメータは非推奨となり、代わりに method パラメータが導入されました。method はより多くのオプション ('linear', 'lower', 'higher', 'nearest', 'midpoint', 'nearest_greater', 'nearest_lower') を提供し、計算方法をより厳密に指定できるようになっています。しかし、基本的な5つの補間方法の考え方はinterpolationと同じです。

“`python

NumPy 1.22以降の場合、methodを使うのが推奨

p = 25
linear_percentile_method = np.percentile(data, p, method=’linear’)
print(f”{p}パーセンタイル (method=’linear’): {linear_percentile_method}”)

出力: 25パーセンタイル (method=’linear’): 3.25

“`

7. 欠損値(NaN)の扱い

実際のデータには、欠損値(Not a Number, NaN)が含まれていることがよくあります。NumPyのpercentile関数は、デフォルトでは欠損値を含むデータに対して呼び出されると、結果としてNaNを返すか、エラーを発生させることがあります(バージョンや状況による)。欠損値を除外してパーセンタイルを計算したい場合は、np.nanpercentile関数を使用します。

np.nanpercentileは、計算を行う前に配列からNaN値を自動的に除外します。その他の使い方は基本的にnp.percentileと同じです。

“`python

欠損値を含むサンプルデータを作成

data_with_nan = np.array([1, 2, 3, 4, np.nan, 6, 7, 8, 9, 10])

print(f”欠損値を含むデータ: {data_with_nan}”)

np.percentileを使うとNaNになる可能性が高い(または警告/エラー)

percentile_with_nan = np.percentile(data_with_nan, 50)

print(f”np.percentile(data_with_nan, 50): {percentile_with_nan}”)

(実行するとNaNが出力されることが多い)

np.nanpercentileで欠損値を除外して計算

NaNを除外するとデータは [1, 2, 3, 4, 6, 7, 8, 9, 10] (9個) になる

nan_median_value = np.nanpercentile(data_with_nan, 50)
print(f”np.nanpercentile(data_with_nan, 50): {nan_median_value}”)

出力例: np.nanpercentile(data_with_nan, 50): 6.0

(9個のデータ [1,2,3,4,6,7,8,9,10] の中央値は 6)

複数のパーセンタイルも同様

nan_percentiles = np.nanpercentile(data_with_nan, [25, 50, 75])
print(f”np.nanpercentile(data_with_nan, [25, 50, 75]): {nan_percentiles}”)

出力例: np.nanpercentile(data_with_nan, [25, 50, 75]): [3. 6. 8.5]

(9個のデータ [1,2,3,4,6,7,8,9,10] のQ1は3, Q2は6, Q3は8.5)

“`

多次元配列とaxisパラメータもnp.nanpercentileで同様に利用できます。

“`python
data_2d_with_nan = np.array([[10, 20, np.nan, 40, 50],
[15, 25, 35, 45, 55]])

print(f”\n欠損値を含む2次元配列:\n{data_2d_with_nan}”)

各列の50パーセンタイルを欠損値を除外して計算 (axis=0)

nan_median_per_column = np.nanpercentile(data_2d_with_nan, 50, axis=0)
print(f”\n各列の50パーセンタイル (NaN除外, axis=0): {nan_median_per_column}”)

出力例: 各列の50パーセンタイル (NaN除外, axis=0): [12.5 22.5 35. 42.5 52.5]

(列2 [nan, 35] の中央値は 35)

“`

データに欠損値が含まれる可能性がある場合は、np.nanpercentileを使うことで、欠損値の存在を気にせずにパーセンタイル計算を進めることができます。

8. パーセンタイルの応用例

NumPyのpercentile関数を使って計算できるパーセンタイルは、データの分布を理解し、分析を行う上で様々な形で応用できます。

8.1. 四分位数の計算と5数要約

前述の通り、四分位数(Q1, Q2, Q3)はそれぞれ25, 50, 75パーセンタイルです。これらの値は、データの分布の中心位置とばらつきの度合いを示す重要な指標となります。

さらに、データの5数要約 (Five-Number Summary) は、以下の5つの値で構成され、データの分布を簡潔にまとめることができます。

  1. 最小値 (Minimum)
  2. 第1四分位数 (Q1 – 25th Percentile)
  3. 中央値 (Q2 – 50th Percentile)
  4. 第3四分位数 (Q3 – 75th Percentile)
  5. 最大値 (Maximum)

NumPyを使ってこれらを計算してみましょう。

“`python
data = np.array([85, 70, 90, 65, 75, 95, 60, 80, 70, 55, 88, 72, 68, 78, 82])

最小値と最大値

min_val = np.min(data)
max_val = np.max(data)

四分位数を計算

q1 = np.percentile(data, 25)
q2_median = np.percentile(data, 50) # 中央値
q3 = np.percentile(data, 75)

print(f”データ: {data}”)
print(“\n5数要約:”)
print(f”最小値 (Min): {min_val}”)
print(f”第1四分位数 (Q1): {q1}”)
print(f”中央値 (Q2/Median): {q2_median}”)
print(f”第3四分位数 (Q3): {q3}”)
print(f”最大値 (Max): {max_val}”)

出力例:

5数要約:

最小値 (Min): 55

第1四分位数 (Q1): 69.0

中央値 (Q2/Median): 75.0

第3四分位数 (Q3): 83.5

最大値 (Max): 95

“`

この5数要約から、データの範囲、中心、そして中心部のばらつき具合(Q3 – Q1)を把握できます。箱ひげ図(Box Plot)は、この5数要約を視覚化したものです。

8.2. 四分位範囲(IQR)の計算

四分位範囲(IQR: Interquartile Range)は、Q3とQ1の差であり、データの中心50%が収まる範囲を示します。データのばらつきを示すロバストな指標です。

“`python

IQRを計算

iqr = q3 – q1
print(f”\n四分位範囲 (IQR): {iqr}”)

出力例: 四分位範囲 (IQR): 14.5

“`

IQRが小さいほど、データの中央部分は密集していると言えます。

8.3. 外れ値の特定

IQRは、データの外れ値を特定するための一般的なルールの基盤としても使用されます。伝統的なIQRベースの外れ値ルールは以下の通りです。

  • 下限の閾値: Q1 – 1.5 * IQR
  • 上限の閾値: Q3 + 1.5 * IQR

この閾値よりも小さい値、または大きい値は、潜在的な外れ値と見なされます。

“`python

外れ値識別のための閾値を計算

lower_bound = q1 – 1.5 * iqr
upper_bound = q3 + 1.5 * iqr

print(f”\n外れ値の下限閾値: {lower_bound}”)
print(f”外れ値の上限閾値: {upper_bound}”)

外れ値の特定

outliers = data[(data < lower_bound) | (data > upper_bound)]

print(f”\n特定された外れ値: {outliers}”)

出力例:

外れ値の下限閾値: 47.25

外れ値の上限閾値: 105.25

特定された外れ値: []

(この例のデータセットには外れ値と判定される値はありません)

外れ値を含むデータで試す

data_with_outlier = np.append(data, [0, 150]) # 0と150を外れ値として追加

min_val_ol = np.min(data_with_outlier)
max_val_ol = np.max(data_with_outlier)
q1_ol = np.percentile(data_with_outlier, 25)
q3_ol = np.percentile(data_with_outlier, 75)
iqr_ol = q3_ol – q1_ol
lower_bound_ol = q1_ol – 1.5 * iqr_ol
upper_bound_ol = q3_ol + 1.5 * iqr_ol
outliers_ol = data_with_outlier[(data_with_outlier < lower_bound_ol) | (data_with_outlier > upper_bound_ol)]

print(f”\n外れ値を含むデータ: {data_with_outlier}”)
print(f”外れ値の下限閾値 (含む): {lower_bound_ol}”)
print(f”外れ値の上限閾値 (含む): {upper_bound_ol}”)
print(f”特定された外れ値 (含む): {outliers_ol}”)

出力例 (概算):

外れ値を含むデータ: [ 85. 70. 90. 65. 75. 95. 60. 80. 70. 55. 88. 72. 68. 78. 82. 0. 150.]

外れ値の下限閾値 (含む): 48.75

外れ値の上限閾値 (含む): 103.25

特定された外れ値 (含む): [ 0. 150.]

“`

この方法は、正規分布を仮定しない、データの形状に依存しない外れ値検出手法として広く使われています。

8.4. データの比較

パーセンタイルは、異なるデータセットや異なるグループ間でのデータの比較に有効です。例えば、2つのクラスのテスト結果を比較する場合、平均点だけでなく、各クラスの25, 50, 75パーセンタイルを比較することで、点数のばらつきや上位・下位層の状況をより詳細に把握できます。

“`python
class_a_scores = np.array([75, 80, 85, 70, 90, 65, 88, 78, 82, 70])
class_b_scores = np.array([60, 62, 65, 70, 72, 75, 80, 85, 90, 92])

print(f”クラスAの点数: {class_a_scores}”)
print(f”クラスBの点数: {class_b_scores}”)

クラスAのパーセンタイル

q_a = np.percentile(class_a_scores, [25, 50, 75])
print(f”\nクラスAの [25, 50, 75] パーセンタイル: {q_a}”)
print(f”クラスAの平均点: {np.mean(class_a_scores)}”)

クラスBのパーセンタイル

q_b = np.percentile(class_b_scores, [25, 50, 75])
print(f”クラスBの [25, 50, 75] パーセンタイル: {q_b}”)
print(f”クラスBの平均点: {np.mean(class_b_scores)}”)

出力例:

クラスAの [25, 50, 75] パーセンタイル: [70. 76.5 84.25]

クラスAの平均点: 77.3

クラスBの [25, 50, 75] パーセンタイル: [66.25 73.5 83.75]

クラスBの平均点: 75.1

“`

この結果から、平均点はクラスAがわずかに高いですが、Q1とQ2を見るとクラスBの方が全体的に点数が低い層が多いことが分かります。Q3はほぼ同じであることから、上位層の点数には大きな差がないことも見て取れます。このようにパーセンタイルを比較することで、平均値だけでは得られない洞察を得られます。

8.5. 多次元データへの応用例(再掲)

複数の数値変数を持つデータセット(例えば、学生の国語、数学、理科の点数が列になっているデータフレーム)がある場合、axisパラメータを使って各科目ごとのパーセンタイルを計算し、科目の難易度や学生の得意不得意の分布を比較できます。

“`python

学生30人の国語、数学、理科の点数を模倣

scores_multi = np.random.randint(40, 100, size=(30, 3)) # 30行 x 3列のデータ

print(f”学生の科目別点数 (一部):\n{scores_multi[:5]}”) # 最初5人分を表示

各科目の [25, 50, 75] パーセンタイルを計算 (axis=0: 列ごと)

subject_percentiles = np.percentile(scores_multi, [25, 50, 75], axis=0)

print(f”\n各科目の [25, 50, 75] パーセンタイル:\n{subject_percentiles}”)

出力例 (毎回ランダムなので変わります):

各科目の [25, 50, 75] パーセンタイル:

[[56. 57.75 56.5 ] <- 25パーセンタイル (Q1)

[72. 77.5 74. ] <- 50パーセンタイル (中央値)

[86.75 89. 89.75]] <- 75パーセンタイル (Q3)

(各列がそれぞれの科目に対応)

“`

この出力から、例えば数学のQ2が最も高い傾向があり、数学の平均点が高いかもしれない、といった推測ができます。また、Q3-Q1(IQR)を見ることで、科目ごとの点数のばらつきの違いも比較できます。

8.6. パーセンタイルランク

np.percentileは値からパーセンタイルを計算しますが、逆に値が与えられたときにそれが何パーセンタイルに位置するか(パーセンタイルランク)を知りたい場合もあります。NumPyには直接この機能はありませんが、scipy.stats.percentileofscore関数を使用することができます。パーセンタイルランクは、個々のデータポイントがデータセット全体の中でどの位置にあるかを評価するのに役立ちます。

9. パーセンタイルと他の統計量の関係

パーセンタイル(特に中央値や四分位数)は、平均値や標準偏差といった他の一般的な統計量とどのように関連し、どのように使い分けるべきでしょうか?

  • 中央値 vs. 平均値:

    • 中央値(50パーセンタイル)は、データを真ん中で二分する値です。データセットが歪んでいる場合や外れ値が存在する場合、中央値はこれらの影響を受けにくく、データの中央をより代表する値となります。
    • 平均値は、データセット内の全ての値の合計に基づいているため、外れ値や歪みの影響を大きく受けます。データが正規分布に近い場合や、全ての値を考慮した「重心」を知りたい場合に適しています。
    • 使い分け: データの分布が対称的で外れ値がない場合は、平均値と中央値は近い値になり、どちらを使っても大きな問題はありません。しかし、データが歪んでいる(例: 所得分布、販売データなど)場合や外れ値がある場合は、中央値の方がデータの典型的な値をよりよく表します。
  • IQR vs. 標準偏差:

    • IQR (Q3 – Q1) は、データの中央50%のばらつきを示します。Q1とQ3は外れ値に強いため、IQRもばらつきのロバストな指標です。データの中心部分の広がりを把握したい場合に有用です。
    • 標準偏差は、各データポイントが平均値からどれだけ離れているかを示す指標であり、データセット全体のばらつきを表します。平均値と同様、全ての値に基づいて計算されるため、外れ値に影響されやすいです。データが正規分布に近い場合や、平均値周りの典型的なばらつきを知りたい場合に適しています。
    • 使い分け: データが歪んでいる場合や外れ値が多い場合は、IQRの方がばらつきの典型的な範囲をよりよく表します。データの分布が正規分布に近い場合は、標準偏差の方が理論的な分析(信頼区間など)に使いやすいため、好まれることが多いです。

パーセンタイルは、平均値や標準偏差がデータの全体像を捉えきれないような、非対称な分布や外れ値を含むデータセットの分析において、特に強力なツールとなります。分布の形状を数値的に理解するために、中心傾向(中央値)、ばらつき(IQR)、そして特定のパーセンタイル値(例: 10, 90パーセンタイルなど)を組み合わせて分析することが推奨されます。

10. パーセンタイルを使う上での注意点

パーセンタイルは非常に有用ですが、使用する際にはいくつかの注意点があります。

  1. データ数: データ数が非常に少ない場合、パーセンタイルの計算(特に補間を伴う場合)の結果は不安定になりやすく、その解釈には注意が必要です。データポイントが少ないと、パーセンタイル位置のわずかな違いが、採用されるデータポイントや補間結果に大きく影響する可能性があります。
  2. 離散データ: データが少数の離散的な値しか取らない場合(例: 評価が1~5の整数値のみ)、計算されたパーセンタイルが実際のデータポイント以外の値になることがあります(特に線形補間など)。この場合、interpolationパラメータを適切に選択するか、補間された値の意味を慎重に解釈する必要があります。
  3. 補間方法の選択: 前述の通り、補間方法によって同じデータと同じパーセンタイル値でも結果が異なることがあります。分析の目的に最も合った補間方法を選択し、もし結果を他者と共有する場合は、どの補間方法を使用したかを明記することが望ましいです。
  4. 解釈の文脈: パーセンタイル値は常にデータセット全体の文脈の中で解釈されるべきです。「90パーセンタイルが〇〇だった」という事実は、そのデータセットがどのような特性を持つか、そして〇〇という値がそのデータセットにおいてどのような位置づけにあるかを意味します。異なるデータセット間でパーセンタイル値を比較する際は、データ収集方法や母集団の違いなどを考慮する必要があります。
  5. ソートによる計算コスト: パーセンタイル計算は、基本的にデータを小さい順にソートする必要があります。大規模なデータセットの場合、ソートの計算コストが大きくなる可能性があります。ただし、NumPyのような最適化されたライブラリでは、この処理は非常に効率的に行われます。

11. まとめと次のステップ

本記事では、データの分布を理解することの重要性から始め、パーセンタイルの概念、そしてNumPyのpercentile関数とその詳細な使い方について解説しました。

  • データの分布は、データセット全体の形状、中心、ばらつき、外れ値などを把握するために不可欠です。
  • パーセンタイルは、データを小さい順に並べたときに、特定の割合(k%)がその値以下になるような値を指し、データの相対的な位置や順位を理解するのに役立ちます。
  • NumPyのnp.percentile関数は、単一または複数のパーセンタイル値を効率的に計算するための強力なツールです。
  • axisパラメータを使うことで、多次元配列の特定の軸に沿った計算が可能です。
  • interpolation(またはmethod)パラメータは、パーセンタイルがデータポイント間に来る場合の計算方法を詳細に制御でき、データの性質や分析目的に応じて適切な方法を選択することが重要です。
  • np.nanpercentile関数は、欠損値(NaN)を含むデータセットから欠損値を除外してパーセンタイルを計算できます。
  • パーセンタイルは、四分位数やIQRの計算、5数要約の作成、外れ値の特定、および異なるデータセット間の比較など、データの分布分析において幅広く応用できます。
  • 中央値やIQRといったパーセンタイルベースの統計量は、外れ値や歪みに強く、データのロバストな要約として有用です。

NumPyのpercentile関数を使いこなすことは、データ分析における分布理解を深める上で非常に強力な武器となります。ぜひ、お手元のデータを使って実際に様々なパーセンタイル値を計算し、データの隠れたパターンや特徴を発見してみてください。

次のステップとして、以下のことを学んでみることをお勧めします。

  • データの視覚化: MatplotlibやSeabornといったライブラリを使って、ヒストグラム、箱ひげ図(ボックスプロット)、バイオリンプロットなどを描画し、パーセンタイルと視覚的な分布を関連付けて理解を深めましょう。箱ひげ図は、5数要約(Min, Q1, Median, Q3, Max)を直接的に表現するグラフです。
  • 様々な分布: 正規分布だけでなく、対数正規分布、ポアソン分布、指数分布など、様々な確率分布について学び、それぞれの分布がどのような現象を表し、パーセンタイルがどのように計算・解釈されるかを理解しましょう。
  • 統計的仮説検定: データの分布に関する仮定が、T検定やANOVAなどの統計的仮説検定にどのように影響するかを学びましょう。
  • より高度な分位数: パーセンタイルの一般化であるクォンタイル回帰など、統計モデリングにおける分位点の活用について学ぶのも良いでしょう。

データの分布を理解することは、単なる数値計算に留まらず、データが持つ意味や背景にある現象を深く洞察するための鍵となります。NumPyのpercentile関数は、その強力なツールの一つとして、あなたのデータ分析能力をさらに向上させてくれるでしょう。


総単語数: 約5100語


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール