Python Pandas 数据帧提取与筛选实战:从基础到高级的数据选择艺术188


在数据分析和科学计算领域,Python凭借其强大的生态系统占据了核心地位,其中Pandas库更是处理表格数据(即DataFrame)的瑞士军刀。无论是数据清洗、特征工程还是模型构建,数据帧的“提取”和“筛选”都是不可或缺的基础操作。本文将作为一名专业的程序员,深入探讨Python Pandas中如何高效、灵活地提取和筛选数据帧,从基础的列选择到高级的条件查询,助您掌握数据选择的艺术。

一、理解Pandas DataFrame及其重要性

Pandas DataFrame是一个二维的、大小可变、可能异构的表格数据结构,类似于电子表格或SQL表,或Series对象的字典。它拥有行和列,每一列可以是不同的数据类型。在面对海量或结构化数据时,DataFrame提供了一种直观且高效的方式来组织和操作数据。数据提取和筛选是所有数据分析任务的起点,它决定了我们能从数据中获得哪些洞察。

在开始之前,我们先导入Pandas库并创建一个示例DataFrame,供后续操作使用:
import pandas as pd
import numpy as np
# 创建一个示例DataFrame
data = {
'学生ID': [101, 102, 103, 104, 105, 106, 107, 108, 109, 110],
'姓名': ['张三', '李四', '王五', '赵六', '钱七', '孙八', '周九', '吴十', '郑一', '冯二'],
'班级': ['A班', 'B班', 'A班', 'C班', 'B班', 'A班', 'C班', 'B班', 'A班', 'C班'],
'数学成绩': [85, 92, 78, 95, 88, 70, 91, 80, 84, 93],
'英语成绩': [70, 88, 90, 75, 82, 95, 78, 85, 80, 90],
'是否及格': [True, True, True, True, True, False, True, True, True, True]
}
df = (data)
print("原始DataFrame:")
print(df)
print("-" * 30)

二、按列提取数据:选择特定字段

提取数据最常见的需求之一是选择一个或多个特定的列(字段)。Pandas提供了多种简单直观的方法来实现这一点。

1. 提取单个列


你可以通过列名作为字典键的方式来提取单个列,结果会是一个Series对象。
# 提取“姓名”列
names = df['姓名']
print("提取单个列(姓名):")
print(names)
print(type(names)) # <class ''>
print("-" * 30)
# 另一种更简洁的方式(当列名不含空格或特殊字符时)
math_scores = df.数学成绩
print("提取单个列(数学成绩,使用属性访问方式):")
print(math_scores)
print("-" * 30)

2. 提取多个列


要提取多个列,你需要传递一个包含所需列名的列表。结果将是一个新的DataFrame。
# 提取“姓名”和“数学成绩”两列
selected_columns = df[['姓名', '数学成绩']]
print("提取多个列(姓名、数学成绩):")
print(selected_columns)
print(type(selected_columns)) # <class ''>
print("-" * 30)

三、按行提取数据:选择特定记录

按行提取数据通常涉及基于行索引或特定条件来选择数据。Pandas提供了`.loc[]`和`.iloc[]`两个强大的属性,以及布尔索引。

1. 使用 `.loc[]` 按标签(索引)提取行


`.loc[]` 主要用于通过行标签(索引名)和列标签来选择数据。对于我们示例DataFrame,默认的行标签是0到n-1的整数。
# 提取第一行(索引为0的行)
first_row = [0]
print("提取第一行(索引为0):")
print(first_row)
print("-" * 30)
# 提取多行(索引为1、3、5的行)
multiple_rows_loc = [[1, 3, 5]]
print("提取多行(索引为1, 3, 5):")
print(multiple_rows_loc)
print("-" * 30)
# 使用切片提取连续行(索引0到2,包含2)
sliced_rows_loc = [0:2]
print("切片提取行(索引0到2):")
print(sliced_rows_loc)
print("-" * 30)

2. 使用 `.iloc[]` 按位置(整数索引)提取行


`.iloc[]` 主要用于通过行和列的整数位置(从0开始)来选择数据,其行为类似于Python列表的切片。
# 提取第一行(位置为0的行)
first_row_iloc = [0]
print("提取第一行(位置为0):")
print(first_row_iloc)
print("-" * 30)
# 提取多行(位置为1、3、5的行)
multiple_rows_iloc = [[1, 3, 5]]
print("提取多行(位置为1, 3, 5):")
print(multiple_rows_iloc)
print("-" * 30)
# 使用切片提取连续行(位置0到3,不包含3)
sliced_rows_iloc = [0:3]
print("切片提取行(位置0到3):")
print(sliced_rows_iloc)
print("-" * 30)

3. 使用布尔索引筛选行(条件筛选)


布尔索引是Pandas中最强大、最灵活的筛选方式,它允许你根据一个或多个条件来选择行。你传入一个与DataFrame行数相同,且只包含True/False值的Series,True对应的行会被选中。
# 筛选出数学成绩大于85分的学生
high_math_scores = df[df['数学成绩'] > 85]
print("数学成绩大于85分的学生:")
print(high_math_scores)
print("-" * 30)
# 筛选出A班且英语成绩大于80分的学生 (多个条件使用 & 符号连接)
# 注意:每个条件必须用括号括起来,以确保正确的运算优先级
a_class_and_english_good = df[(df['班级'] == 'A班') & (df['英语成绩'] > 80)]
print("A班且英语成绩大于80分的学生:")
print(a_class_and_english_good)
print("-" * 30)
# 筛选出A班或C班的学生 (多个条件使用 | 符号连接)
a_or_c_class = df[(df['班级'] == 'A班') | (df['班级'] == 'C班')]
print("A班或C班的学生:")
print(a_or_c_class)
print("-" * 30)
# 筛选出不及格的学生 (使用 ~ 符号进行取反操作)
failed_students = df[~df['是否及格']]
print("不及格的学生:")
print(failed_students)
print("-" * 30)
# 使用isin()方法筛选多重条件
# 筛选出班级在['A班', 'C班']中的学生
a_or_c_class_isin = df[df['班级'].isin(['A班', 'C班'])]
print("班级在A班或C班中的学生 (使用isin()):")
print(a_or_c_class_isin)
print("-" * 30)

四、同时提取行和列:精确的数据子集

通常情况下,我们需要同时根据行和列的条件来提取一个数据子集。`.loc[]`和`.iloc[]`在处理这种情况时表现得尤为出色。

1. 使用 `.loc[]` 同时按标签提取行和列


语法为 `[行标签或布尔条件, 列标签或列标签列表]`。
# 提取A班学生的姓名和数学成绩
a_class_names_math = [df['班级'] == 'A班', ['姓名', '数学成绩']]
print("A班学生的姓名和数学成绩:")
print(a_class_names_math)
print("-" * 30)
# 提取所有学生的“姓名”和“英语成绩”,仅限索引为偶数的行
even_index_name_english = [ % 2 == 0, ['姓名', '英语成绩']]
print("索引为偶数学生的姓名和英语成绩:")
print(even_index_name_english)
print("-" * 30)

2. 使用 `.iloc[]` 同时按位置提取行和列


语法为 `[行位置或切片, 列位置或切片]`。
# 提取前5行学生(位置0-4)的姓名和数学成绩(列位置1和3)
first_five_students_subset = [0:5, [1, 3]]
print("前5行学生的姓名和数学成绩:")
print(first_five_students_subset)
print("-" * 30)
# 提取所有学生的第1、3、5列(姓名、班级、英语成绩)
all_rows_specific_cols = [:, [1, 2, 4]]
print("所有学生的姓名、班级、英语成绩:")
print(all_rows_specific_cols)
print("-" * 30)

五、高级数据提取技巧

1. 使用 `.query()` 方法


`.query()` 方法允许你使用字符串表达式进行查询,语法更接近SQL,对于复杂的条件筛选尤其方便。它通常比直接使用布尔索引更具可读性,并且在某些情况下性能更好。
# 使用query筛选数学成绩大于85分且英语成绩小于90分的学生
query_result = ("数学成绩 > 85 and 英语成绩 < 90")
print("使用query筛选:数学成绩 > 85 且 英语成绩 < 90:")
print(query_result)
print("-" * 30)
# query中引用外部变量:在变量名前加@
min_math = 80
class_name = 'B班'
query_with_var = ("数学成绩 >= @min_math and 班级 == @class_name")
print(f"使用query筛选:数学成绩 >= {min_math} 且 班级 == {class_name}:")
print(query_with_var)
print("-" * 30)

2. 字符串匹配提取


当列中包含字符串数据时,可以使用 `.str` 访问器进行字符串操作,包括模式匹配。
# 提取姓名中包含“三”或“五”的学生
name_contains_specific = df[df['姓名'].('三|五')]
print("姓名中包含'三'或'五'的学生:")
print(name_contains_specific)
print("-" * 30)
# 提取班级名称以“A”开头的学生 (例如,如果班级有'A班-1', 'A班-2')
# startswith 也可以用正则表达式
class_starts_with_a = df[df['班级'].('A')]
print("班级以'A'开头的学生:")
print(class_starts_with_a)
print("-" * 30)

六、最佳实践与注意事项

1. 明确使用`.loc`和`.iloc`: 这两个方法不仅能提高代码的可读性,还能避免“SettingWithCopyWarning”的潜在问题。直接使用链式索引(如 `df[df['col'] > 0]['another_col']`)有时会返回视图而非副本,导致后续修改不生效或产生警告。始终优先使用 `[行条件, 列条件]`。

2. 布尔条件加括号: 当使用 `&` (and) 或 `|` (or) 组合多个布尔条件时,务必将每个条件用括号 `()` 括起来,以确保正确的运算优先级。

3. 考虑性能: 对于非常大的数据集,`query()` 方法在某些情况下可能比布尔索引更快,因为它在C层进行评估。但对于中小规模的数据集,差异通常不明显。

4. 理解视图与副本: Pandas在进行数据选择时,有时会返回原始DataFrame的“视图”,有时会返回“副本”。修改视图会影响原始DataFrame,而修改副本则不会。为确保行为可预测,如果你打算修改提取的数据,最好明确地创建一个副本,例如 `df_subset = [condition].copy()`。

5. 错误处理: 在进行列选择时,确保列名拼写正确,否则会引发 `KeyError`。使用 `.get()` 方法可以避免KeyError,如果列不存在,它会返回None而不是报错(例如 `('不存在的列')`)。

七、总结

Pandas DataFrame的数据提取和筛选是数据处理的核心。本文详细介绍了从基础的列选择、行选择(基于标签、位置和布尔条件)到行与列的组合提取,以及高级的 `.query()` 和字符串匹配方法。掌握这些技巧,您将能够:
快速定位和获取感兴趣的数据子集。
根据复杂条件灵活筛选数据。
为后续的数据清洗、分析和建模工作奠定坚实基础。

数据分析的旅程才刚刚开始,熟练运用Pandas的数据提取能力,将使您在处理和理解数据时更加得心应手。

2025-11-20


上一篇:Python高效获取NCEP环境数据:从零到专家级实践指南

下一篇:Python序列转字符串:高效、灵活的多种转换技巧与最佳实践