pandas Index 对象 API 完全指南:从基础索引到 MultiIndex 与时间索引
【免费下载链接】pandasFlexible and powerful data analysis / manipulation library for Python, providing labeled data structures similar to R data.frame objects, statistical functions, and much more项目地址: https://gitcode.com/gh_mirrors/pa/pandas
导读
本文以 pandas 官方 API 参考文档doc/source/reference/indexing.rst为骨架,系统梳理 pandas 中全部索引(Index)对象的公开 API:从通用的Index基类属性与方法,到RangeIndex、CategoricalIndex、IntervalIndex、MultiIndex,再到时间序列场景下的DatetimeIndex、TimedeltaIndex、PeriodIndex,并配合仓库源码(pandas/core/indexes/)说明各方法的底层行为与适用场景。读完本文,你将能够按图索骥地选用正确的索引 API 完成标签定位、对齐、合并、切片、时间重采样与多层级选取等实战任务。
提示:pandas 官方建议——下面列举的许多方法,在包含索引的对象(Series/DataFrame)上同样可用,实践中应优先使用对象级方法(如
Series.loc、DataFrame.reindex),再考虑直接调用索引方法。
一、Index:所有索引对象的基石
Index是 pandas 中所有索引类型的抽象基类,定义在 pandas/core/indexes/base.py。它是不可变的、可哈希的、有序的标签集合,其实现混合了 NumPy 数组语义(继承IndexOpsMixin)与 pandas 对象语义(继承PandasObject)。
其余所有具体索引类型(RangeIndex、CategoricalIndex、IntervalIndex、MultiIndex、DatetimeIndex、TimedeltaIndex、PeriodIndex)都继承自Index,因此本节列出的属性和方法对全部索引类型通用。
1.1 基础属性(Properties)
官方 API 参考中Index一节列出的属性,按功能可归为以下几组:
| 分组 | 属性 | 含义 |
|---|---|---|
| 底层数据 | values、array、dtype | 标签的底层 NumPy 数组 / 扩展数组表示,及其 dtype |
| 结构信息 | shape、ndim、size、empty、nbytes、T | 维度、长度、是否为空、内存占用(字节)、转置 |
| 唯一性 / 单调性 | is_unique、has_duplicates、is_monotonic_increasing、is_monotonic_decreasing | 是否唯一、是否含重复项、是否单调递增/递减 |
| 缺失值 | hasnans | 是否含 NaN |
| 类型推断 | inferred_type | 推断出的元素类型(如"integer"、"string"、"datetime64"等) |
| 名称 | name、names | 索引名称(MultiIndex有多个名称) |
| 内存 | memory_usage | 索引占用的内存字节数 |
源码佐证与实战建议:is_monotonic_increasing/is_monotonic_decreasing直接决定了get_loc在重复标签下返回slice还是布尔掩码(见下文 3.1 节);has_duplicates与is_unique则在Index.get_indexer、Index.join等对齐逻辑中被广泛依赖,用于选择哈希查找还是线性查找路径。判断一个索引是否为内存友好的稀疏表示,可用memory_usage(deep=True)统计真实占用。
1.2 修改与计算(Modifying and computations)
| 类别 | 方法 | 说明 |
|---|---|---|
| 聚合与归约 | all、any、min、max、argmin、argmax | 逻辑归约与极值定位 |
| 复制与重命名 | copy、rename | 复制索引 / 修改name(返回新对象) |
| 删除与去重 | delete、drop、drop_duplicates、duplicated、unique、nunique、value_counts | 按位置/标签删除、去重、计数 |
| 插入与填充 | insert、repeat、replace、where、putmask、take | 插入新标签、重复元素、替换值、条件填充、按位置选取 |
| 对齐与相等 | equals、identical、factorize、reindex | 值级比较(equals与identical的区别见下)、因子化编码、按新标签重排 |
容易混淆的两个方法:
equals:仅比较值是否相等(忽略名称与 dtype 的细微差异),返回bool;identical:要求索引对象完全一致,包括name、dtype 等元数据(源码见 pandas/core/indexes/base.py 同文件中的实现)。
1.3 MultiIndex 兼容与缺失值处理
- MultiIndex 兼容:
set_names(批量/按层级设置名称)、droplevel(移除指定层级,返回层级更少的索引或MultiIndex)。 - 缺失值:
fillna(用给定值填充 NaN 标签)、dropna(剔除 NaN 标签)、isna、notna(返回布尔数组)。
1.4 类型转换(Conversion)
| 方法 | 说明 |
|---|---|
astype | 转换 dtype,如Index([1,2,3]).astype("str") |
infer_objects | 尝试将 object 数组推断为更具体的类型 |
item | 当索引恰好只有一个元素时返回该标量 |
map | 用映射函数/字典批量变换标签,返回新Index |
ravel | 展平为一维数组 |
to_list | 转为 Python list(同tolist) |
to_series | 转为以自身为索引的Series |
to_frame | 转为单列DataFrame |
to_numpy | 转为 NumPy 数组 |
view | 以不同 dtype 视图查看底层数据(通常用于int64→timedelta64等) |
1.5 排序(Sorting)
argsort:返回排序后的位置索引数组;sort_values:返回排序后的新Index(默认升序,可用ascending=False);searchsorted:在有序索引中二分查找插入位置,返回整数数组(side="left"/"right"控制重复值时的插入边界)。
1.6 合并 / 连接 / 集合操作(Combining / joining / set operations)
| 方法 | 语义 |
|---|---|
append | 追加另一个索引,返回新索引(重复项保留) |
join | 按标签对齐合并,how支持"left"、"right"、"inner"、"outer" |
intersection | 交集 |
union | 并集(默认排序) |
difference | 差集(出现在自身、不出现在对方) |
symmetric_difference | 对称差集 |
1.7 标签定位与切片(Selecting)
这是Index最核心的一组方法,直接支撑Series.loc/DataFrame.loc的底层实现:
| 方法 | 返回 | 典型场景 |
|---|---|---|
get_loc(key) | int/slice/ 布尔数组 | 单个标签的整数位置 |
get_indexer(target) | np.ndarray[np.intp] | 批量标签对齐,未匹配返回-1 |
get_indexer_for(target) | np.ndarray[np.intp] | 允许非唯一索引,无条件返回位置 |
get_indexer_non_unique(target) | (indexer, missing) | 非唯一索引下的批量定位 |
get_level_values(level) | Index | 取指定层级的全部标签 |
get_slice_bound(label, side) | int | 切片边界整数 |
slice_indexer(start, end) | slice | 构造标签区间切片 |
slice_locs(start, end) | (int, int) | 切片起止位置 |
isin(values) | 布尔数组 | 判断每个标签是否属于给定集合 |
asof(label) | 标量 | 返回小于等于label的最大标签(时间序列场景常用) |
asof_locs(where, mask) | 位置数组 | asof的向量化版本 |
源码解析(get_loc):pandas/core/indexes/base.py 中get_loc的返回类型完全取决于索引特征:
- 唯一索引 → 返回
int; - 含重复但单调的索引 → 返回
slice; - 含重复且非单调的索引 → 返回布尔掩码数组。
>>> unique_index = pd.Index(list("abc")) >>> unique_index.get_loc("b") 1 >>> monotonic_index = pd.Index(list("abbc")) >>> monotonic_index.get_loc("b") slice(1, 3, None) >>> non_monotonic_index = pd.Index(list("abcb")) >>> non_monotonic_index.get_loc("b") array([False, True, False, True])其内部实现为self._engine.get_loc(casted_key)——每种索引类型都绑定了一个底层的哈希/区间查找引擎(Index._engine_type),get_loc的性能与语义均由此引擎决定。
源码解析(get_indexer):pandas/core/indexes/base.py 中get_indexer支持三个关键参数:
method:None(仅精确匹配,默认)、"pad"/"ffill"(取前一个值)、"backfill"/"bfill"(取后一个值)、"nearest"(取最近值,平局时偏向更大的标签);limit:非精确匹配时,连续匹配的最大标签数;tolerance:非精确匹配的最大距离,要求abs(index[indexer] - target) <= tolerance,可为标量或与索引等长的列表类对象。
返回值中,未匹配的目标标签位置标记为-1:
>>> index = pd.Index(["c", "a", "b"]) >>> index.get_indexer(["a", "b", "x"]) array([ 1, 2, -1])二、Numeric Index:RangeIndex
RangeIndex定义在 pandas/core/indexes/range.py,是不可变的单调整数区间索引,仅在 64 位整数范围内表示单调区间,是内存最省、速度最快的一种索引;当用户未显式提供索引时,DataFrame与Series默认使用它作为行索引。
它的构造与 Python 内置range完全一致:start(省略时默认为 0)、stop(开区间,不含终点)、step(步长)。dtype与copy参数仅为了与其他索引类型接口统一而保留,实际不生效。
>>> list(pd.RangeIndex(5)) [0, 1, 2, 3, 4] >>> list(pd.RangeIndex(0, 10, 2)) [0, 2, 4, 6, 8] >>> list(pd.RangeIndex(2, -10, -3)) [2, -1, -4, -7]与RangeIndex相关的公开 API 还包括:
start/stop/step:三个只读属性,直接返回区间的起止与步长;from_range(rng, name=None):类方法,从 Pythonrange对象构造RangeIndex。
性能要点:由于只保存(start, stop, step)三元组而非全部元素,RangeIndex的内存占用不随长度增长,且其底层引擎固定为libindex.Int64Engine(见 pandas/core/indexes/range.py),查找与切片均为 O(1)/O(log n) 级别。
三、CategoricalIndex:分类索引
CategoricalIndex(定义于 pandas/core/indexes/category.py)底层由Categorical数据支撑,用于值域很小但重复度极高的标签场景。它的 dtype 不再是普通 NumPy dtype,而是CategoricalDtype,因此被归类为"扩展数组支持的索引"(NDArrayBackedExtensionIndex)。
3.1 分类组件(Categorical components)
| 属性 / 方法 | 说明 |
|---|---|
codes | 每个元素对应的整数编码(指向categories的位置) |
categories | 分类类别(去重后的取值集合) |
ordered | 是否为有序分类 |
rename_categories | 重命名类别(长度必须与类别数一致) |
reorder_categories | 重排类别顺序(集合相同,仅改变顺序) |
add_categories | 追加新类别 |
remove_categories | 移除类别(已使用的值会变为 NaN) |
remove_unused_categories | 删除未被实际使用的类别 |
set_categories | 整体替换类别集合 |
as_ordered/as_unordered | 切换有序 / 无序状态 |
3.2 修改与计算
CategoricalIndex.map:按映射字典或函数转换每个标签;CategoricalIndex.equals:分类语义下的相等比较(忽略类别顺序差异)。
适用场景:当一列标签是有限的枚举值(如省份、状态码)且需要按类别顺序排序、做类别级聚合时,优先使用CategoricalIndex,可显著节省内存并让排序语义与业务一致。
四、IntervalIndex:区间索引
IntervalIndex(定义于 pandas/core/indexes/interval.py)用于表示左闭右开、左开右闭等形式的数值区间,每个元素是一个Interval。它是 pandas 区间分箱(如pd.cut、Interval列)的索引载体。
4.1 构造与组件
三个常用类方法构造器:
| 构造器 | 语义 |
|---|---|
from_arrays(left, right, closed="right") | 由左右端点数组构造 |
from_tuples(intervals) | 由(left, right)元组序列构造 |
from_breaks(breaks, closed="right") | 由有序断点数组构造,自动生成相邻区间 |
组件属性:
| 属性 / 方法 | 说明 |
|---|---|
left/right | 左端点数组 / 右端点数组 |
mid | 区间中点 |
closed | 开闭约定("left"、"right"、"both"、"neither") |
length | 区间长度 |
values | 底层IntervalArray |
is_empty | 是否存在空区间 |
is_overlapping | 区间是否存在重叠(会触发完整检测) |
is_non_overlapping_monotonic | 是否互不重叠且单调(可启用快速查找) |
4.2 定位、包含与变换
get_loc/get_indexer:对区间索引做标签定位(精确匹配区间端点);set_closed:切换开闭约定,返回新索引;contains(value):判断标量是否落在任一区间内,返回布尔数组;overlaps(other):判断区间与给定区间是否重叠;to_tuples:将区间转为(left, right)元组数组。
典型用例:配合pd.cut生成分组区间后,用IntervalIndex作为分组键或DataFrame的索引,可基于get_indexer快速完成"数值 → 所属区间"的映射查找。
五、MultiIndex:多层级索引
MultiIndex(定义于 pandas/core/indexes/multi.py)是 pandas 处理多维标签的核心结构,本质是"若干层标签的笛卡尔组合"。它同样继承自Index,因此 1.1~1.7 节的通用属性和方法(values、dropna、join、get_indexer等)同样适用。
5.1 构造器(MultiIndex constructors)
官方 API 列出四个类方法:
| 构造器 | 说明 |
|---|---|
from_arrays(arrays, sortorder=None, names=None) | 由若干等长数组构造,第 i 个数组构成第 i 层 |
from_tuples(tuples, names=None) | 由(level0, level1, ...)元组序列构造 |
from_product(iterables, names=None) | 由若干可迭代对象的笛卡尔积构造 |
from_frame(df, names=None) | 由DataFrame的列构造 |
源码示例(from_arrays):pandas/core/indexes/multi.py 中,每个输入数组对应一层,各数组第 i 个元素共同组成第 i 个元组:
>>> arrays = [[1, 1, 2, 2], ["red", "blue", "red", "blue"]] >>> pd.MultiIndex.from_arrays(arrays, names=("number", "color")) MultiIndex([(1, 'red'), (1, 'blue'), (2, 'red'), (2, 'blue')], names=['number', 'color'])from_tuples适用于"元组列表"形态的数据;from_product则适合生成因子实验式的全组合标签:
>>> pd.MultiIndex.from_product([["a", "b"], [1, 2]]) MultiIndex([('a', 1), ('a', 2), ('b', 1), ('b', 2)])5.2 属性(MultiIndex properties)
| 属性 | 说明 |
|---|---|
names | 各层名称(元组) |
levels | 各层去重后的标签列表 |
codes | 各层标签在levels中的整数编码 |
nlevels | 层级数量 |
levshape | 各层大小组成的元组 |
dtypes | 各层 dtype |
5.3 组件操作(MultiIndex components)
| 方法 | 说明 |
|---|---|
set_levels/set_codes | 替换层级标签 / 编码 |
to_flat_index | 展平为普通Index(元素为元组) |
to_frame | 转为每层一列的DataFrame |
sortlevel(level) | 按指定层级排序,返回(MultiIndex, indexer) |
droplevel(level) | 移除一个或多个层级 |
swaplevel(i=-2, j=-1) | 交换两个层级的顺序(源码见 pandas/core/indexes/multi.py) |
reorder_levels(order) | 按给定顺序重排层级(源码见 pandas/core/indexes/multi.py) |
remove_unused_levels | 移除codes中未使用的层级值 |
drop/copy/append/truncate | 删除、复制、追加、截断 |
5.4 选取(MultiIndex selecting)
| 方法 | 说明 |
|---|---|
get_loc(key) | 对完整元组键做精确定位 |
get_locs(seq) | 支持跨层级的切片/列表/布尔组合式定位(见 pandas/core/indexes/multi.py),是df.loc[(slice(None), "x"), :]的底层支撑 |
get_loc_level(key, level=0, drop_level=True) | 同时返回位置与剩余层级,部分标签选取的核心实现(见 pandas/core/indexes/multi.py) |
get_indexer(target) | 批量对齐,未匹配返回-1 |
get_level_values(level) | 返回指定层级的全部标签 |
5.5 IndexSlice:多层切片利器
pd.IndexSlice(即pd.IndexSlice = pd.IndexSlice语法糖,也可写作pd.IndexSlice[:])用于在.loc中表达跨层级的混合切片:
>>> idx = pd.MultiIndex.from_product([["a", "b"], [1, 2, 3]]) >>> df = pd.DataFrame({"v": range(6)}, index=idx) >>> df.loc[pd.IndexSlice["a", 1:2], :] v a 1 0 2 1IndexSlice让"第一层选 'a',第二层切 1:2"这样的混合选取一行写出,避免嵌套元组的繁琐。
六、DatetimeIndex:日期时间索引
DatetimeIndex(定义于 pandas/core/indexes/datetimes.py)是时间序列分析的主角,底层以纳秒/微秒等整数编码存储,支持时区、频率推断与丰富的日期组件访问。其基础能力(get_loc、reindex、join等)全部继承自Index,此处只列出时间特有的 API。
6.1 时间 / 日期组件(Time/date components)
| 分组 | 属性 |
|---|---|
| 日历字段 | year、month、day、quarter、dayofyear/day_of_year、dayofweek/day_of_week、weekday |
| 时刻字段 | hour、minute、second、microsecond、nanosecond |
| 日期对象 | date(datetime.date数组)、time(datetime.time数组)、timetz(带时区的time) |
| 边界判断 | is_month_start、is_month_end、is_quarter_start、is_quarter_end、is_year_start、is_year_end、is_leap_year |
| 频率与时区 | freq、freqstr、inferred_freq、tz |
| 底层编码 | asi8(int64 纳秒编码)、unit(时间单位,如"ns"、"us") |
注意:dayofyear/day_of_year、dayofweek/day_of_week是新旧命名并存,官方推荐使用带下划线的day_of_year、day_of_week形式。
6.2 选取(Selecting)
indexer_at_time(time):返回一天中指定时刻所在位置的整数数组,用于日内切片;indexer_between_time(start_time, end_time, include_start=True, include_end=True):返回介于两个时刻之间的位置数组。
两者是df.between_time(...)的底层实现,适合"每天 09:30-15:00"这类日内时段过滤。
6.3 时间特有操作(Time-specific operations)
| 方法 | 说明 |
|---|---|
normalize | 时间归零到当天 00:00:00 |
strftime | 按格式串转字符串数组 |
snap(freq) | 将时间"吸附"到最近的一个频率边界 |
tz_convert/tz_localize | 时区转换 / 时区本地化(tz_localize可用ambiguous、nonexistent参数处理歧义时刻) |
round/floor/ceil | 按频率取整(如"h"、"5min"),round的ambiguous与nonexistent参数处理边界情况 |
month_name/day_name | 返回月份 / 星期名称(支持locale参数) |
6.4 转换(Conversion)
as_unit(unit):切换底层时间单位("s"、"ms"、"us"、"ns"),可避免超大范围数据溢出;to_period(freq):转为PeriodIndex(例如把日级时间转为"M"月周期);to_pydatetime:转为 Pythondatetime.datetime数组;to_series/to_frame:转为Series/DataFrame;to_julian_date:转为儒略日数值。
6.5 统计方法
DatetimeIndex.mean():时间平均值(需单调且有频率,或显式给出skipna);DatetimeIndex.std():时间标准差。
七、TimedeltaIndex:时间差索引
TimedeltaIndex(定义于 pandas/core/indexes/timedeltas.py)表示相对时间间隔(如"1 day 02:00:00"),底层同样以 int64 编码存储。
7.1 组件(Components)
| 属性 | 说明 |
|---|---|
days | 天数部分(不含时分秒换算) |
seconds | 秒部分(0~86399) |
microseconds | 微秒部分 |
nanoseconds | 纳秒部分(0~999) |
components | 返回一个DataFrame,含days/hours/minutes/seconds/...各列 |
inferred_freq | 推断的频率字符串 |
asi8 | int64 底层编码 |
unit | 底层时间单位 |
7.2 转换与方法
as_unit(unit):切换单位("s"、"ms"、"us"、"ns");to_pytimedelta:转为 Pythondatetime.timedelta数组;to_series/to_frame:转为Series/DataFrame;round/floor/ceil:按频率取整;mean():时间差均值。
典型场景:对"耗时/间隔"数据建索引,或把DataFrame中两列时间相减得到TimedeltaIndex后进行区间分箱与重采样。
八、PeriodIndex:周期索引
PeriodIndex(定义于 pandas/core/indexes/period.py)表示离散的时间周期(如 "2024-01" 这个月、某个季度),与DatetimeIndex(连续时间点)互补。每个元素是一个Period,含固定的freq。
8.1 属性(Properties)
| 属性 | 说明 |
|---|---|
year、month、day、hour、minute、second | 日历/时刻字段 |
quarter、qyear | 季度序号、所属年度(财年) |
week、weekofyear、weekday、dayofweek/day_of_week | 周相关字段 |
dayofyear/day_of_year | 年内第几天 |
days_in_month/daysinmonth | 当月天数 |
start_time/end_time | 周期起止时刻 |
freq、freqstr | 频率对象 / 频率字符串 |
is_leap_year | 是否闰年 |
asi8 | int64 周期序号编码 |
8.2 方法(Methods)
| 方法 | 说明 |
|---|---|
asfreq(freq) | 频率转换(如"D"→"M"),支持how="start"/"end"指定对齐方式 |
strftime(fmt) | 按格式转字符串 |
to_timestamp(freq=None, how="start") | 转为DatetimeIndex(周期起点或终点) |
from_fields(year, month, day=None, ...) | 由字段数组构造(类方法) |
from_ordinals(ordinals, freq) | 由周期序号构造(类方法) |
典型场景:df.resample("M").mean()后索引即为PeriodIndex;财务季度统计、同比/环比聚合时常用asfreq在日/月/季/年频率间切换。
九、索引选择速查表
| 数据类型 | 推荐索引 | 关键 API |
|---|---|---|
| 默认整数行号 | RangeIndex | start/stop/step、from_range |
| 小值域重复标签 | CategoricalIndex | categories/codes、rename_categories、set_categories |
| 数值区间(分箱) | IntervalIndex | from_breaks、contains、overlaps、get_indexer |
| 多维复合标签 | MultiIndex | from_arrays/from_product、get_loc_level、get_locs、IndexSlice |
| 时间点序列 | DatetimeIndex | tz_localize/tz_convert、floor/ceil、to_period、indexer_between_time |
| 时间间隔序列 | TimedeltaIndex | components、round/floor/ceil、as_unit |
| 离散周期序列 | PeriodIndex | asfreq、to_timestamp、from_fields |
选择原则:先判断标签是整数区间、分类、区间、多维、时间点、时间差还是周期,再决定索引类型;DatetimeIndex偏重连续时间点运算,PeriodIndex偏重离散周期聚合,两者可通过to_period/to_timestamp双向转换。
十、深入阅读路径
- API 参考原文档:doc/source/reference/indexing.rst(
Index至PeriodIndex全部条目); - 索引核心实现:pandas/core/indexes/base.py(
Index类,get_loc见 L3757,get_indexer见 L3818); - 各索引子类:pandas/core/indexes/range.py、pandas/core/indexes/category.py、pandas/core/indexes/interval.py、pandas/core/indexes/multi.py、pandas/core/indexes/datetimes.py、pandas/core/indexes/timedeltas.py、pandas/core/indexes/period.py;
- 索引对象如何被 Series/DataFrame 使用:可对照 pandas/core/series.py 与 pandas/core/frame.py 中的
.index相关入口继续阅读。
本文以当前仓库中的 API 参考文档为骨架,结合源码验证各方法的签名与语义;示例代码基于仓库所示签名整理,实际使用前请以仓库内对应版本的 docstring 为准。
【免费下载链接】pandasFlexible and powerful data analysis / manipulation library for Python, providing labeled data structures similar to R data.frame objects, statistical functions, and much more项目地址: https://gitcode.com/gh_mirrors/pa/pandas
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考