:一文吃透 Index 索引体系与时间索引实战)
文档教程【免费下载链接】Python-100-DaysPython - 100天从新手到大师项目地址https://gitcode.com/GitHub_Trending/py/Python-100-Days点击查看免费下载导读Index是 pandas 中为Series与DataFrame提供索引服务的核心类型它支撑起数据排序sort_index、数据对齐运算与合并时的关键机制以及对数据的快速检索索引运算。本篇文章基于《Python-100 天从新手到大师》项目中 深入浅出pandas-6 的完整内容系统讲解RangeIndex范围索引、CategoricalIndex分类索引、MultiIndex多级索引、IntervalIndex间隔索引与DatetimeIndex日期时间索引五大子类型的创建、运算与实战用法并结合仓库内的 notebook 与数据文件给出可直接运行的示例。读完本文你将掌握用索引驱动分组聚合、时间重采样、时区转换等高级数据分析能力。本文是 pandas 系列教程的第六篇前序内容分别覆盖了 Series/DataFrame 基础、分组聚合与数据透视、透视与描述性统计 以及 同比环比与窗口计算建议按顺序学习。认识 Indexpandas 数据结构的“坐标轴”Index类型为Series和DataFrame提供索引服务。由于DataFrame表示的是二维数据它的行和列分别拥有自己的索引即index和columns。有了索引我们就可以排序数据通过sort_index方法按索引排序对齐数据在运算和合并数据时pandas 会依据索引将不同对象对齐这是非常关键的行为快速检索基于索引的运算如loc定位、分组能高效定位目标数据。创建Index对象很简单通常只需要三个参数参数含义data作为索引的数据dtype索引的数据类型name索引的名称由于Index本身也是一维的数据索引它的方法和属性与Series非常类似。你可以创建一个Index对象然后尝试把之前学过的属性和方法在Index类型上验证一遍很快就能摸清它的行为规律。范围索引RangeIndex范围索引是由具有单调性的整数构成的索引它本质上就是整数范围的一种高效表示底层不会把每个整数都显式存储。创建方式有两种使用RangeIndex构造器或使用其类方法from_range。下面的代码为 12 个月的销售数据创建了从1到12的范围索引sales_data np.random.randint(400, 1000, 12) index pd.RangeIndex(1, 13, name月份) ser pd.Series(datasales_data, indexindex) ser输出月份 1 703 2 705 3 557 4 943 5 961 6 615 7 788 8 985 9 921 10 951 11 874 12 609 dtype: int64使用要点RangeIndex的优势在于内存效率极高——它只需记录起点、终点与步长而不需要保存全部元素。当你用pd.read_excel/pd.read_csv读取数据且没有指定索引列时pandas 默认就会生成一个0 ~ N-1的RangeIndex这在仓库配套的 day06.ipynb 的 DataFrame 输出中可以看到例如RangeIndex: 244 entries, 0 to 243。分类索引CategoricalIndex分类索引由定类尺度有限且可枚举的类别构成。当我们需要按索引将数据分组后再做聚合时分类索引就能派上用场——它保证分组聚合能够按类别语义进行。分类索引还有一个独特的reorder_categories方法可以为索引指定一个顺序分组聚合的结果将按该指定顺序呈现。先创建一个按水果类别索引的Seriessales_data [6, 6, 7, 6, 8, 6] index pd.CategoricalIndex( data[苹果, 香蕉, 苹果, 苹果, 桃子, 香蕉], categories[苹果, 香蕉, 桃子], orderedTrue ) ser pd.Series(datasales_data, indexindex) ser输出苹果 6 香蕉 6 苹果 7 苹果 6 桃子 8 香蕉 6 dtype: int64基于索引分组数据然后使用sum进行求和ser.groupby(level0).sum()输出苹果 19 香蕉 12 桃子 8 dtype: int64重排类别顺序通过reorder_categories指定索引顺序后分组聚合结果的展示顺序也随之改变ser.index index.reorder_categories([香蕉, 桃子, 苹果]) ser.groupby(level0).sum()输出香蕉 12 桃子 8 苹果 19 dtype: int64使用要点categories参数限定了合法类别集合orderedTrue表示类别之间有顺序关系。这在需要按固定业务顺序而非字母/哈希顺序呈现分组结果时非常有用。多级索引MultiIndexMultiIndex用来表示层次或多级索引可以同时从多个维度组织数据。pandas 提供了多个类方法用于创建多级索引类方法用途from_arrays由多个等长数组每层一个构建from_product由多组标签的笛卡尔积构建from_tuples由元组列表构建先看from_tuples的用法tuples [(1, red), (1, blue), (2, red), (2, blue)] index pd.MultiIndex.from_tuples(tuples, names[no, color]) index输出MultiIndex([(1, red), (1, blue), (2, red), (2, blue)], names[no, color])from_arrays的效果与之等价arrays [[1, 1, 2, 2], [red, blue, red, blue]] index pd.MultiIndex.from_arrays(arrays, names[no, color]) index输出MultiIndex([(1, red), (1, blue), (2, red), (2, blue)], names[no, color])基于多级索引创建 Series 与分组聚合sales_data np.random.randint(1, 100, 4) ser pd.Series(datasales_data, indexindex) ser输出no color 1 red 43 blue 31 2 red 55 blue 75 dtype: int64按第一级索引no分组求和ser.groupby(no).sum()输出no 1 74 2 130 dtype: int64按第二级索引color分组求和ser.groupby(level1).sum()输出color blue 106 red 98 dtype: int64提示groupby(no)与groupby(level0)在这里效果一致前者按索引名称分组后者按层级位置分组。多级索引下可以按任意一级进行分组聚合灵活性极高。实战学生成绩表。使用from_product构造“学号 × 学期”的层级索引创建包含 5 名学生期中/期末成绩的DataFramestu_ids np.arange(1001, 1006) semisters [期中, 期末] index pd.MultiIndex.from_product((stu_ids, semisters), names[学号, 学期]) courses [语文, 数学, 英语] scores np.random.randint(60, 101, (10, 3)) df pd.DataFrame(datascores, columnscourses, indexindex) df输出语文 数学 英语 学号 学期 1001 期中 93 77 60 期末 93 98 84 1002 期中 64 78 71 期末 70 71 97 1003 期中 72 88 97 期末 99 100 63 1004 期中 80 71 61 期末 91 62 72 1005 期中 82 95 67 期末 84 78 86进阶聚合根据第一级索引分组按“期中成绩占 25%、期末成绩占 75%”加权计算每个学生每门课的最终成绩df.groupby(level0).agg(lambda x: x.values[0] * 0.25 x.values[1] * 0.75)输出语文 数学 英语 学号 1001 93.00 92.75 78.00 1002 68.50 72.75 90.50 1003 92.25 97.00 71.50 1004 88.25 64.25 69.25 1005 83.50 82.25 81.25使用要点多级索引在“宽表转长表、多维度透视、时间×类别双维度数据”等场景中非常常见。值得一提的是聚合后的DataFrame其列索引同样可能是MultiIndex对象例如下面时间重采样中agg([mean, std])的输出可以通过访问.columns属性来观察其结构。间隔索引IntervalIndex间隔索引使用固定的间隔范围充当索引通常使用interval_range函数创建。它适用于区间分箱、区间查找等场景。index pd.interval_range(start0, end5) index输出IntervalIndex([(0, 1], (1, 2], (2, 3], (3, 4], (4, 5]], dtypeinterval[int64, right])contains 方法检查范围内是否包含某个元素index.contains(1.5)输出array([False, True, False, False, False])overlaps 方法检查一个范围跟其他范围是否有重叠index.overlaps(pd.Interval(1.5, 3.5))输出array([False, True, True, True, False])closed 参数控制区间开闭状态。默认是左开右闭right如果希望间隔范围是左闭右开可以通过closedleft实现如果希望两边都封闭则将closed参数的值赋为bothindex pd.interval_range(start0, end5, closedleft) index输出IntervalIndex([[0, 1), [1, 2), [2, 3), [3, 4), [4, 5)], dtypeinterval[int64, left])间隔索引同样支持datetime64类型的区间例如以“天”为粒度的左闭右闭区间index pd.interval_range(startpd.Timestamp(2022-01-01), endpd.Timestamp(2022-01-04), closedboth) index输出IntervalIndex([[2022-01-01, 2022-01-02], [2022-01-02, 2022-01-03], [2022-01-03, 2022-01-04]], dtypeinterval[datetime64[ns], both])使用要点interval_range还支持freq步长与periods区间个数参数用于控制区间的粒度和数量IntervalIndex常与pd.cut/pd.qcut分箱结果配合使用是处理年龄段、价格区间、时间窗口等数据的利器。日期时间索引DatetimeIndexDatetimeIndex是众多索引中最复杂也最重要的一种几乎所有时间序列分析都离不开它。我们通常使用date_range()函数来创建日期时间索引它有五个非常重要的参数参数含义start起始日期时间end结束日期时间periods生成周期个数freq采样频率tz时区按周期数生成periods10表示在起止时间内均匀生成 10 个时间点pd.date_range(2021-1-1, 2021-6-30, periods10)输出DatetimeIndex([2021-01-01, 2021-01-21, 2021-02-10, 2021-03-02, 2021-03-22, 2021-04-11, 2021-05-01, 2021-05-21, 2021-06-10, 2021-06-30], dtypedatetime64[ns], freqNone)按频率生成freqW表示采样周期为一周默认以星期日为一周的开始pd.date_range(2021-1-1, 2021-6-30, freqW)输出DatetimeIndex([2021-01-03, 2021-01-10, 2021-01-17, 2021-01-24, 2021-01-31, 2021-02-07, 2021-02-14, 2021-02-21, 2021-02-28, 2021-03-07, 2021-03-14, 2021-03-21, 2021-03-28, 2021-04-04, 2021-04-11, 2021-04-18, 2021-04-25, 2021-05-02, 2021-05-09, 2021-05-16, 2021-05-23, 2021-05-30, 2021-06-06, 2021-06-13, 2021-06-20, 2021-06-27], dtypedatetime64[ns], freqW-SUN)说明freqW会默认星期日作为一周的开始如果你希望星期一表示一周的开始可以将其修改为freqW-MON。你也可以尝试把该参数的值修改为12H、M、Q等看看会发生什么——不难猜到H是小时、M是月末、Q是季度末的含义。DatetimeIndex 与 DateOffset 的偏移运算DatetimeIndex可以与DateOffset类型进行运算设置一个时间差让时间向前或向后偏移。向前偏移 2 天index pd.date_range(2021-1-1, 2021-6-30, freqW) index - pd.DateOffset(days2)输出DatetimeIndex([2021-01-01, 2021-01-08, 2021-01-15, 2021-01-22, 2021-01-29, 2021-02-05, 2021-02-12, 2021-02-19, 2021-02-26, 2021-03-05, 2021-03-12, 2021-03-19, 2021-03-26, 2021-04-02, 2021-04-09, 2021-04-16, 2021-04-23, 2021-04-30, 2021-05-07, 2021-05-14, 2021-05-21, 2021-05-28, 2021-06-04, 2021-06-11, 2021-06-18, 2021-06-25], dtypedatetime64[ns], freqNone)向后偏移 2 小时 10 分钟index pd.DateOffset(hours2, minutes10)输出DatetimeIndex([2021-01-03 02:10:00, 2021-01-10 02:10:00, 2021-01-17 02:10:00, 2021-01-24 02:10:00, 2021-01-31 02:10:00, 2021-02-07 02:10:00, 2021-02-14 02:10:00, 2021-02-21 02:10:00, 2021-02-28 02:10:00, 2021-03-07 02:10:00, 2021-03-14 02:10:00, 2021-03-21 02:10:00, 2021-03-28 02:10:00, 2021-04-04 02:10:00, 2021-04-11 02:10:00, 2021-04-18 02:10:00, 2021-04-25 02:10:00, 2021-05-02 02:10:00, 2021-05-09 02:10:00, 2021-05-16 02:10:00, 2021-05-23 02:10:00, 2021-05-30 02:10:00, 2021-06-06 02:10:00, 2021-06-13 02:10:00, 2021-06-20 02:10:00, 2021-06-27 02:10:00], dtypedatetime64[ns], freqNone)用 asfreq 对时间索引抽样如果Series或DataFrame使用了DatetimeIndex类型的索引就可以通过asfreq()方法指定一个时间频率对数据进行抽样。这里沿用前一篇教程深入浅出pandas-5使用过的百度股票数据baidu_df pd.read_excel(data/2022年股票数据.xlsx, sheet_nameBIDU, index_colDate) baidu_df.sort_index(inplaceTrue) baidu_df.asfreq(5D)输出大家可能注意到了每 5 天抽取 1 天有可能会抽中非交易日那么对应的列都变成了空值。为了解决这个问题使用asfreq方法时可以通过method参数来指定一种填充空值的方法将相邻的交易日数据填入进来baidu_df.asfreq(5D, methodffill)输出用 resample 对时间数据重采样当使用DatetimeIndex索引时也可以通过resample()方法基于时间对数据进行重采样——它相当于根据时间周期对数据进行了分组操作分组之后还可以进行聚合统计。例如按月1M计算均值baidu_df.resample(1M).mean()也可以同时聚合多种统计量baidu_df.resample(1M).agg([mean, std])提示注意上面输出的DataFrame的列索引是一个MultiIndex对象——(Close, mean)、(Close, std)这样的组合正好呼应了前文介绍的多级索引。你可以访问该DataFrame的columns属性确认这一点。时区本地化与时区转换如果要实现日期时间的时区转换可以先用tz_localize()方法将日期时间本地化到某个时区baidu_df baidu_df.tz_localize(Asia/Chongqing) baidu_df在对时间本地化之后再使用tz_convert()方法就可以实现转换时区baidu_df.tz_convert(America/New_York)使用要点tz_localize是为“没有时区信息”的时间数据赋予一个基准时区tz_convert则是在已有本地化结果的基础上做不同时区之间的换算。注意转换前必须先完成本地化顺序不能颠倒。小结如何选择索引类型索引类型适用场景常用创建方式关键方法RangeIndex默认整数位置索引、内存高效的连续整数RangeIndex()/from_range与整数索引切片配合CategoricalIndex定类尺度、按固定类别顺序分组聚合CategoricalIndex(data, categories, ordered)reorder_categoriesMultiIndex多维度层级数据、按任一层级分组聚合from_arrays/from_product/from_tuplesgroupby(level...)IntervalIndex区间分箱、区间包含与重叠判断interval_range(start, end, closed, freq)contains/overlapsDatetimeIndex时间序列、抽样、重采样、时区处理date_range(start, end, periods, freq, tz)asfreq/resample/tz_localize/tz_convert/DateOffset本文对应的完整教程位于仓库的 深入浅出pandas-6配套的 notebook 与数据文件如 day06.ipynb、2022年股票数据.xlsx位于 code/res均可直接运行复现。如果你的数据使用了DatetimeIndex索引那么很可能要进行时间序列分析——关于时间序列分析的方法和模型并不是本章节要探讨的内容我们会在其他专栏中继续分享。赞分享文档教程【免费下载链接】Python-100-DaysPython - 100天从新手到大师项目地址https://gitcode.com/GitHub_Trending/py/Python-100-Days点击查看免费下载相关推荐Python-100-Days 数据分析实战pandas 数据透视与可视化深入浅出 pandas-4 精讲Python 100 Days 数据分析实战pandas 数据透视与可视化深入浅出 pandas 4 精讲 数据准备与清洗只是数据分析的前半程真正产生业文档教程pyspark.pandas 索引对象IndexAPI 全面指南Index、MultiIndex、CategoricalIndex 与时间索引实战pyspark.pandas 索引对象IndexAPI 全面指南Index、MultiIndex、CategoricalIndex 与时间索引实战 pys大数据数据分析批处理流处理机器学习图计算pandas Index 对象 API 完全指南从基础索引到 MultiIndex 与时间索引pandas Index 对象 API 完全指南从基础索引到 MultiIndex 与时间索引 导读 本文以 pandas 官方 API 参考文档 doc/s数据分析数据科学数据处理上一篇cult-ui深度解析50动画组件如何提升用户体验下一篇TVBoxOSC开源智能电视盒应用开发终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考