目录
进阶篇25. 数据迭代与遍历 (iterrows, itertuples)
1. 引言
在使用 Pandas 进行数据分析时,往往需要对 DataFrame 中的每一行或每一列进行迭代操作。虽然 Pandas 内置了丰富的向量化方法,可以高效地对整个数据集进行批量运算,但在某些场景下,我们仍需要逐行或逐条处理数据。常见的迭代方法主要有两种:
- iterrows():按行返回一个 (索引, Series) 对,用于逐行遍历 DataFrame。
- itertuples():按行返回一个具名元组,速度通常比 iterrows() 更快,且内存开销更低。
本文将详细介绍这两种方法的使用原理、优缺点和实际案例,帮助你在数据遍历和处理时做出最佳选择。
2. iterrows() 方法
2.1 基本原理
iterrows()
是 Pandas DataFrame 中常用的一种迭代方法。它会逐行返回一个元组,其中第一个元素是行索引,第二个元素是一个 Pandas Series 对象,表示该行的数据。数学上,若 DataFrame 有
n
n
n 行,则 iterrows() 会返回
n
n
n 个元组:
{
(
i
,
s
i
)
∣
i
=
0
,
1
,
…
,
n
−
1
}
\{ (i, s_i) \mid i = 0, 1, \dots, n-1 \}
{(i,si)∣i=0,1,…,n−1}
其中
s
i
s_i
si 是第
i
i
i 行的 Series 表示。
2.2 示例代码
下面是一个使用 iterrows() 迭代 DataFrame 行的简单示例:
import pandas as pd
# 创建示例 DataFrame
data = {
'Name': ['Alice', 'Bob', 'Charlie'],
'Age': [25, 30, 35],
'Score': [85, 90, 95]
}
df = pd.DataFrame(data)
# 使用 iterrows() 逐行遍历 DataFrame
for index, row in df.iterrows():
print(f"Index: {index}, Name: {row['Name']}, Age: {row['Age']}, Score: {row['Score']}")
输出结果:
Index: 0, Name: Alice, Age: 25, Score: 85
Index: 1, Name: Bob, Age: 30, Score: 90
Index: 2, Name: Charlie, Age: 35, Score: 95
2.3 优点与缺点
优点:
- 使用简单直观,每次返回一个 Series,可以像操作字典一样通过列名获取数据。
- 对于小规模数据,代码易于理解和调试。
缺点:
- 性能较低。由于 iterrows() 在 Python 层面逐行构造 Series,当数据量较大时,会显著降低运行速度。
- 数据类型可能不完全保留。在 iterrows() 返回的 Series 中,原 DataFrame 的数据类型有时会被转换为通用的 Python 数据类型。
3. itertuples() 方法
3.1 基本原理
itertuples()
方法同样用于按行迭代 DataFrame,但它返回的是一个具名元组(namedtuple),其中包含行内的所有数据,并且字段名对应 DataFrame 的列名。数学上,它将 DataFrame 的每一行映射为一个元组:
{
t
i
∣
i
=
0
,
1
,
…
,
n
−
1
}
\{ t_i \mid i = 0, 1, \dots, n-1 \}
{ti∣i=0,1,…,n−1}
其中
t
i
t_i
ti 是一个具名元组,允许通过属性访问方式获取每个字段的值。
3.2 示例代码
下面是使用 itertuples() 的示例:
import pandas as pd
# 创建示例 DataFrame
data = {
'Name': ['Alice', 'Bob', 'Charlie'],
'Age': [25, 30, 35],
'Score': [85, 90, 95]
}
df = pd.DataFrame(data)
# 使用 itertuples() 逐行遍历 DataFrame
for row in df.itertuples(index=True, name='PandasRow'):
print(f"Index: {row.Index}, Name: {row.Name}, Age: {row.Age}, Score: {row.Score}")
输出结果:
Index: 0, Name: Alice, Age: 25, Score: 85
Index: 1, Name: Bob, Age: 30, Score: 90
Index: 2, Name: Charlie, Age: 35, Score: 95
3.3 优点与缺点
优点:
- 性能高于 iterrows()。由于返回的是具名元组,迭代速度更快,特别适用于大规模数据遍历。
- 内存开销更低,因为元组的构造开销比 Series 低。
缺点:
- 访问方式略不直观,需要通过属性访问(例如 row.Name)而不是键索引。
- 如果 DataFrame 的列名包含空格或特殊字符,可能需要处理字段名的格式。
4. 性能对比
在大数据集上,两者的性能差异十分明显。下面通过一个简单的性能测试示例,比较 iterrows() 与 itertuples() 的运行时间:
import pandas as pd
import numpy as np
import time
# 创建一个大 DataFrame
df_large = pd.DataFrame({
'A': np.random.rand(100000),
'B': np.random.rand(100000),
'C': np.random.rand(100000)
})
# 使用 iterrows()
start_time = time.time()
for _, row in df_large.iterrows():
_ = row['A'] + row['B'] + row['C']
iterrows_time = time.time() - start_time
# 使用 itertuples()
start_time = time.time()
for row in df_large.itertuples():
_ = row.A + row.B + row.C
itertuples_time = time.time() - start_time
print(f"iterrows() 耗时: {iterrows_time:.4f} 秒")
print(f"itertuples() 耗时: {itertuples_time:.4f} 秒")
通常情况下,itertuples() 的运行速度会显著快于 iterrows(),因此在大数据遍历场景下更推荐使用 itertuples()。[citeturn1search0]
5. 使用场景与最佳实践
5.1 使用场景
- 数据转换与调试
对于小规模数据集或调试过程中,需要逐行检查数据时,iterrows() 提供了直观的 Series 访问方式。 - 大规模数据处理
在处理大数据集时,应尽量使用 itertuples(),以获得更高的遍历效率。 - 自定义计算
对于需要对每一行执行复杂自定义操作的情况,结合 itertuples() 可显著降低计算时间。
5.2 最佳实践
- 尽量使用向量化操作。很多情况下,不必逐行遍历,而可以利用 Pandas 内置的向量化函数完成相同任务。
- 对于必须逐行处理的操作,优先选择 itertuples(),以提升性能。
- 当数据集较小且需要直观调试时,可以使用 iterrows()。
- 注意 iterrows() 返回的 Series 中可能会改变数据类型,使用 itertuples() 时请确保列名格式符合要求。
6. 常见问题与调试技巧
6.1 数据类型变化问题
在 iterrows() 中,返回的 Series 可能会将数据类型统一转换为 Python 内置类型,导致与原始 DataFrame 类型不一致。如果对数据类型有严格要求,建议使用 itertuples() 或尽量利用向量化操作。
6.2 索引问题
在使用 itertuples() 时,如果设置了 index=True
,返回的具名元组中会包含一个名为 “Index” 的属性。注意在访问时要考虑这一点,以避免混淆。
6.3 调试技巧
- 逐步测试
在对 DataFrame 进行迭代时,先用小数据集进行测试,确保逻辑正确,再扩展到大数据集。 - 使用 try/except 捕获错误
在迭代过程中,如果存在不规范的数据格式,建议使用 try/except 块捕获异常,并记录错误信息以便调试。 - 结合 logging 输出调试信息
通过 logging 模块输出迭代过程中关键信息,便于定位问题。
例如:
import logging
logging.basicConfig(level=logging.INFO)
for row in df_large.itertuples():
try:
result = row.A + row.B + row.C
except Exception as e:
logging.error(f"Error processing row {row.Index}: {e}")
7. 总结
本文详细介绍了 Pandas 中两种常用的迭代与遍历方法:
- iterrows()
- 每次返回一个 (索引, Series) 对,适合调试和小数据集,但性能较低且可能引起数据类型变化问题。
- itertuples()
- 每次返回一个具名元组,性能优越且内存占用低,适合大数据集的迭代操作。
我们通过多个示例展示了两者的使用方法和性能对比,并提出了在实际应用中如何选择和调试的最佳实践。总的来说,在需要逐行处理数据时,尽量采用 itertuples() 来提高效率;同时,在可能的情况下,优先使用向量化操作以充分利用 Pandas 和 NumPy 的高效计算能力。
掌握这些数据迭代与遍历技巧,将为你在数据预处理、特征工程和模型构建过程中提供灵活且高效的解决方案。
8. 参考资料
- Pandas 官方文档:Iteration: iterrows and itertuples citeturn1search0
- 《Python for Data Analysis》 by Wes McKinney
希望本文能帮助你全面了解和灵活运用 Pandas 中的 iterrows() 与 itertuples() 方法,在实际数据处理过程中根据数据规模和需求做出最优选择,提升数据迭代的效率和代码的执行速度。不断实践与优化,将使你在数据科学的工作中更加游刃有余。