pandas 核心数据结构:Series 与 DataFrame

发布时间:2026/10/4 20:13:14
pandas 核心数据结构:Series 与 DataFrame 摘要pandas 是 Python 数据分析中最常用的表格处理工具。理解Series和DataFrame的结构、索引、列、数据类型和对齐规则是后续数据读取、清洗、筛选、分组和合并的基础。本文从一维 Series 和二维 DataFrame 开始介绍创建、查看、索引、切片、修改、类型转换和数据对齐并通过订单数据示例建立一套可复用的基本操作习惯。一、背景与问题业务数据通常不是单一的数字数组而是包含多个字段的表格order_idcustomeramountstatusA001Alice1200paidA002Bob800pending使用嵌套列表处理这类数据时需要手动维护列名、数据类型和行位置代码容易出现以下问题通过位置访问字段可读性差。插入或删除列后索引关系容易错乱。缺失值和不同类型混在一起判断复杂。多张表关联需要手动编写循环。pandas 用带标签的数据结构表达表格使列名、索引和数据类型成为代码的一部分。二、核心概念1. SeriesSeries 是带索引的一维数据。可以把它理解为“带标签的数组”index value east 1200 south 800 north 1560Series 的核心属性包括属性说明index每个元素对应的标签values底层值dtype数据类型nameSeries 名称shape数据形状2. DataFrameDataFrame 是由多个 Series 按索引对齐组成的二维表格。每一列是一个 Series所有列共享行索引。DataFrame ├─ index ├─ Series: order_id ├─ Series: customer ├─ Series: amount └─ Series: status不同列可以使用不同数据类型但同一列通常应保持类型稳定。3. IndexIndex 是 pandas 数据结构中的标签系统。它既可以是默认整数索引也可以是字符串、日期或多级索引。索引主要用于定位数据。对齐不同 Series。连接和合并表格。表示时间序列位置。索引不是普通的数据列。需要将索引转换为列时可以使用reset_index()。4. 标签对齐pandas 运算默认按标签对齐而不是单纯按位置importpandasaspd leftpd.Series([10,20],index[a,b])rightpd.Series([1,2],index[b,c])print(leftright)结果中a和c因为缺少对应标签会得到缺失值。标签对齐很方便但也要求在运算前确认索引含义。5. 数据类型常见类型包括整数和浮点数。字符串。布尔值。日期时间。分类类型。可空整数和可空布尔类型。类型会影响筛选、排序、聚合、内存和输出格式不能只看表格显示结果判断类型。三、工作原理1. DataFrame 的列式结构DataFrame 以列为核心组织数据。不同列可能拥有不同类型因此处理单列通常比把所有数据转换成同一种 NumPy 类型更自然。读取表格 → 建立列名和索引 → 推断或指定 dtype → 通过标签选择数据 → 返回 Series 或 DataFrame使用链式操作时要注意每一步返回的是原对象、视图还是新对象避免隐式修改带来的错误。2.loc与ilocloc按标签选择。iloc按整数位置选择。df.loc[0,amount]df.iloc[0,2]当索引不是连续整数时loc[0]和iloc[0]的含义可能完全不同。3. 视图与副本对 DataFrame 进行切片后再修改可能产生副本修改警告或无法修改原数据。更明确的方式是使用.loc直接赋值或者在需要独立数据时显式.copy()。4. 缺失值pandas 通常使用NaN、NaT或可空类型表示缺失。缺失值具有特殊传播规则importpandasaspd seriespd.Series([10,None,30])print(series.isna())print(series.fillna(0))缺失值处理不能只做全局填充应根据字段含义和业务规则决定。四、实战示例1. 创建 Seriesimportpandasaspd amountspd.Series([1200.0,800.0,1560.0],index[A001,A002,A003],nameamount,)print(amounts)print(amounts[A002])print(amounts.dtype)2. 创建 DataFrameorderspd.DataFrame({order_id:[A001,A002,A003,A004],customer:[Alice,Bob,Carol,David],amount:[1200.0,800.0,1560.0,620.0],status:[paid,pending,paid,cancelled],})print(orders)print(orders.shape)print(orders.columns.tolist())print(orders.dtypes)3. 查看数据print(orders.head(2))print(orders.tail(2))print(orders.info())print(orders.describe(numeric_onlyTrue))print(orders[status].value_counts(dropnaFalse))info()适合检查列名、非空数量和类型value_counts()适合查看分类字段的分布。4. 选择列amountorders[amount]selectedorders[[order_id,amount,status]]print(type(amount))print(type(selected))选择单列通常返回 Series选择多列返回 DataFrame。5. 使用loc和ilocfirst_orderorders.loc[0]first_amountorders.loc[0,amount]first_twoorders.iloc[0:2,0:3]print(first_order)print(first_amount)print(first_two)使用标签选择时代码表达的是业务字段使用位置选择时代码依赖列和行的位置。6. 条件筛选paid_ordersorders.loc[orders[status]paid]large_ordersorders.loc[orders[amount]1000]selected_ordersorders.loc[(orders[status]paid)(orders[amount]1000),[order_id,amount],]print(selected_orders)多个条件需要使用、|和~并为每个条件加括号。不能直接使用 Python 的and和or处理 Series。7. 新增与修改列ordersorders.copy()orders[is_high_value]orders[amount]1000orders[amount_with_tax]orders[amount]*1.06orders.loc[orders[status]pending,status]待支付print(orders)通过.loc修改满足条件的单元格可以避免链式赋值带来的不确定性。8. 类型转换orders[amount]pd.to_numeric(orders[amount],errorscoerce,)orders[order_date]pd.to_datetime([2026-09-01,2026-09-02,2026-09-03,2026-09-04],errorscoerce,)orders[status]orders[status].astype(string)errorscoerce会把无法转换的值变成缺失值转换后必须继续检查缺失数量不能把异常静默吞掉。9. 重置索引filteredorders.loc[orders[amount]1000].copy()filteredfiltered.reset_index(dropTrue)print(filtered)筛选后保留原索引有时很有用例如追踪原始行需要生成连续展示序号时再重置索引。10. 导入和导出orders.to_csv(output/orders.csv,indexFalse,encodingutf-8-sig,)loadedpd.read_csv(output/orders.csv)导出时是否保留索引、使用什么编码、是否包含缺失值都应成为明确的接口约定。五、常见问题与实践建议1.loc和iloc该怎么选当代码表达业务字段时优先使用loc当处理固定位置、矩阵切片或底层数组时可以使用iloc。避免用位置索引表达容易变化的业务列。2. 为什么筛选后修改会出现警告常见原因是对一个可能由切片产生的对象继续赋值。可以使用resultorders.loc[orders[amount]1000].copy()result.loc[:,level]high3. 为什么字符串列有时是object旧版本或混合内容可能让 pandas 使用object表示字符串列。需要稳定处理时可以显式转换为string并检查其中是否混入数字、列表或其他对象。4. DataFrame 复制会不会很慢大表复制确实会增加内存和时间。先明确是否需要独立副本避免无意义地反复copy()但在需要安全修改筛选结果时显式复制往往比隐式共享更可靠。5. 如何处理重复索引先判断重复索引是否具有业务意义print(orders.index.is_unique)print(orders.index[orders.index.duplicated()])如果索引应该唯一应在读取或转换后立即校验如果允许重复则避免把索引唯一性当作前提。六、进阶思考1. 数据类型与内存大数据表可以从以下方面优化整数列使用合适的位宽。重复字符串转换为category。日期列转换为datetime64。不要让数字列长期保持字符串。优化前后应比较内存和计算结果不能只追求占用更小。2. 链式方法与可读性pandas 支持链式处理summary(orders.loc[orders[status]paid].assign(amount_with_taxlambdaframe:frame[amount]*1.06).loc[:,[order_id,amount_with_tax]])链式代码可以减少中间变量但过长时应拆成具名函数优先保证可读性和可调试性。3. DataFrame 与业务模型DataFrame 适合数据处理不一定适合直接作为整个业务系统的数据模型。进入数据库、API 或领域服务前应明确字段类型、空值语义和主键规则。4. 从单表操作进入分析流程掌握 Series 与 DataFrame 后下一步可以学习读取数据 → 清洗类型 → 条件筛选 → 分组聚合 → 多表合并 → 透视与可视化每一步都应保留数据行数、列名和关键指标的检查。结论Series 是带标签的一维数据DataFrame 是由多个 Series 按索引组织起来的二维表格。loc、iloc、索引对齐、缺失值、类型转换和.copy()是日常 pandas 开发最重要的基础。后续数据读取、清洗和统计分析都建立在这些结构之上。先把数据结构和索引关系理解清楚再扩展到更复杂的业务处理。参考资料pandas 官方文档https://pandas.pydata.org/docs/pandas 用户指南https://pandas.pydata.org/docs/user_guide/NumPy 官方文档https://numpy.org/doc/