- 核心概念:什么是分位数?
- NumPy 中的
quantile函数 (最常用) - Pandas 中的
quantile方法 (Series/DataFrame) - SciPy 中的
scoreatpercentile函数 - 如何选择?
- 完整代码示例
核心概念:什么是分位数?
分位数是将一个数据集划分为大小相等(或近似相等)的连续区间的数值点,通俗地说,它回答了“数据集中某个百分比的数据点小于或等于这个值?”这个问题。

常见的分位数包括:
- 中位数:第 50 百分位数,将数据集平分为两部分。
- 四分位数:
- 第 1 四分位数 (Q1):第 25 百分位数。
- 第 3 四分位数 (Q3):第 75 百分位数。
- 十分位数:将数据集分为 10 份的 9 个点。
- 百分位数:将数据集分为 100 份的 99 个点。
关键点:分位数的计算有多种方法(尤其是在数据点数量有限时),不同库或不同参数可能会得到略微不同的结果,最常用的是线性插值法。
NumPy 中的 numpy.quantile()
这是 NumPy 库中计算分位数的核心函数,也是最直接、最常用的方法之一。
语法
numpy.quantile(a, q, axis=None, out=None, overwrite_input=False, method='linear', keepdims=False)
参数说明
a: array_like,输入的数组或列表。q: float 或 array_like,要计算的分位数,取值范围在[0, 1]之间。5表示中位数,[0.25, 0.5, 0.75]表示计算三个四分位数。axis: int 或 tuple of ints, optional,指定计算分位数的轴,如果为None(默认),则将数组展平后计算。method: str, optional,指定计算分位数的方法,这是不同库结果差异的主要来源,可选值:'linear'(默认): 线性插值,这是最常用、最标准的算法。'lower': 取最近的较低值。'higher': 取最近的较高值。'midpoint': 取两个最近值的中间值。'nearest': 取最近的值。
keepdims: bool, optional,如果为True,则在输出中保留缩减的维度。
示例
import numpy as np
# 创建一个示例数据集
data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
# 1. 计算中位数 (第50百分位数)
median = np.quantile(data, 0.5)
print(f"中位数 (50%): {median}") # 输出: 5.5
# 2. 计算多个分位数 (四分位数)
quartiles = np.quantile(data, [0.25, 0.5, 0.75])
print(f"四分位数 (25%, 50%, 75%): {quartiles}")
# 输出: [3.25 5.5 7.75]
# 3. 指定不同的计算方法
# 使用 'lower' 方法
q_lower = np.quantile(data, 0.9, method='lower')
# 使用 'higher' 方法
q_higher = np.quantile(data, 0.9, method='higher')
print(f"90%分位数 (lower方法): {q_lower}") # 输出: 9
print(f"90%分位数 (higher方法): {q_higher}") # 输出: 10
Pandas 中的 Series.quantile() 和 DataFrame.quantile()
在 Pandas 中,quantile 是一个方法,可以直接应用于 Series(一维数据)和 DataFrame(二维数据)。

语法
Series.quantile(q=0.5, interpolation='linear') DataFrame.quantile(q=0.5, axis=0, numeric_only=True, interpolation='linear')
参数与 NumPy 类似,但有几个不同点:
q参数在 Pandas 中默认值是5。interpolation参数与 NumPy 的method作用相同,但名称不同。- 对于 DataFrame,
axis=0(默认) 表示按列计算,axis=1表示按行计算。 numeric_only是 Pandas 特有的,确保只对数值列进行计算。
示例
import pandas as pd
import numpy as np
# 创建一个 Pandas Series
s = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
# 1. 计算中位数 (默认q=0.5)
median_s = s.quantile()
print(f"Series中位数: {median_s}") # 输出: 5.5
# 2. 计算四分位数
quartiles_s = s.quantile([0.25, 0.5, 0.75])
print(f"Series四分位数:\n{quartiles_s}")
# 输出:
# 0.25 3.25
# 0.50 5.50
# 0.75 7.75
# Name: value, dtype: float64
# 创建一个 Pandas DataFrame
df = pd.DataFrame({
'A': [1, 2, 3, 4, 5],
'B': [10, 20, 30, 40, 50],
'C': ['a', 'b', 'c', 'd', 'e'] # 非数值列
})
# 3. 计算每一列的分位数 (默认axis=0)
# numeric_only=True 会自动忽略'C'列
df_quartiles = df.quantile([0.25, 0.75], numeric_only=True)
print(f"\nDataFrame列分位数:\n{df_quartiles}")
# 输出:
# A B
# 0.25 2.0 20.0
# 0.75 4.0 40.0
# 4. 计算每一行的分位数 (axis=1)
# 需要先将所有列转为数值类型,或者选择数值列
row_quartiles = df[['A', 'B']].quantile(0.5, axis=1)
print(f"\nDataFrame行中位数:\n{row_quartiles}")
# 输出:
# 0 5.5
# 1 11.0
# 2 16.5
# 3 22.0
# 4 27.5
# Name: 0.50, dtype: float64
SciPy 中的 scipy.stats.scoreatpercentile()
SciPy 的统计模块也提供了分位数计算功能,但函数名和参数略有不同。
语法
scipy.stats.scoreatpercentile(a, per, limit=(), interpolation_method='fraction')
参数说明
a: array_like,输入数组。per: float 或 array_like。百分位数,取值范围在[0, 100]之间,注意这里是百分比,不是小数!interpolation_method: str,指定插值方法。'fraction'(默认): 线性插值。'lower','higher','midpoint','nearest': 与 NumPy 类似。
示例
from scipy import stats
import numpy as np
data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
# 计算中位数 (第50百分位数)
# 注意这里的参数是 50, 不是 0.5
median_scipy = stats.scoreatpercentile(data, 50)
print(f"SciPy中位数 (50%): {median_scipy}") # 输出: 5.5
# 计算第90百分位数
q90_scipy = stats.scoreatpercentile(data, 90)
print(f"SciPy 90%分位数: {q90_scipy}") # 输出: 9.9
如何选择?
| 库/函数 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
numpy.quantile() |
最直接、最常用,语法清晰,q参数是小数,符合直觉。 |
需要先导入NumPy。 | 计算单个或多个NumPy数组的分位数,是数据科学任务中的首选。 |
pandas.Series.quantile() |
与Pandas数据结构无缝集成,可以方便地对DataFrame的列或行进行操作。 | 需要先创建Pandas对象。 | 在数据分析流程中,当你已经有一个DataFrame或Series时,直接调用此方法非常方便。 |
scipy.stats.scoreatpercentile() |
SciPy统计工具箱的一部分,功能强大。 | 参数per是百分比,容易与q混淆,不如NumPy/Pandas常用。 |
当你已经在使用SciPy进行其他统计计算时,可以顺手使用,或者当需要计算百分位数(0-100)时。 |
总结建议:
- 如果你手头的是一个NumPy数组,或者只是一个简单的列表,并且想快速计算分位数,用
numpy.quantile()。 - 如果你正在使用Pandas进行数据分析,处理的是DataFrame或Series,用
df.quantile()或s.quantile(),因为它更符合Pandas的操作习惯。 scipy.stats.scoreatpercentile()是一个不错的选择,但使用频率相对较低,主要需要注意参数是百分比。
完整代码示例
下面是一个综合示例,展示了不同库计算结果的对比。

import numpy as np
import pandas as pd
from scipy import stats
# 1. 准备数据
data_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
data_np = np.array(data_list)
data_series = pd.Series(data_list)
# 要计算的分位数
q_to_calculate = [0.25, 0.5, 0.75, 0.9]
print("--- 原始数据 ---")
print(data_list)
print(f"\n计算分位数: {q_to_calculate}\n")
# 2. 使用 NumPy
print("--- NumPy 结果 ---")
np_results = np.quantile(data_np, q_to_calculate)
for q, res in zip(q_to_calculate, np_results):
print(f" {q*100:.0f}% 分位数: {res}")
print()
# 3. 使用 Pandas
print("--- Pandas 结果 ---")
pd_results = data_series.quantile(q_to_calculate)
print(pd_results)
print()
# 4. 使用 SciPy (注意参数是百分比)
print("--- SciPy 结果 ---")
scipy_per = [p * 100 for p in q_to_calculate]
scipy_results = stats.scoreatpercentile(data_np, scipy_per)
for per, res in zip(scipy_per, scipy_results):
print(f" {per:.0f}% 分位数: {res}")
print()
# 5. 演示不同插值方法的结果
print("--- 不同插值方法对比 (计算90%分位数) ---")
data_for_method = np.array([1, 2, 3, 4, 5])
print(f"数据: {data_for_method}")
print(f"线性插值 (默认): {np.quantile(data_for_method, 0.9)}")
print(f"取较低值: {np.quantile(data_for_method, 0.9, method='lower')}")
print(f"取较高值: {np.quantile(data_for_method, 0.9, method='higher')}")
print(f"取最近值: {np.quantile(data_for_method, 0.9, method='nearest')}")
这个例子清晰地展示了,对于相同的数据和相同的分位数定义,不同的库(使用默认参数)会给出相同的结果,但它们的接口和侧重点有所不同,理解这些差异有助于你在不同的场景下选择最合适的工具。
