Pandas使用教程 - 2数据迭代与遍历 (iterrows, itertuples)


进阶篇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,,n1}
其中 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 \} {tii=0,1,,n1}
其中 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()。[citeturn1search0]


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 中的 iterrows() 与 itertuples() 方法,在实际数据处理过程中根据数据规模和需求做出最优选择,提升数据迭代的效率和代码的执行速度。不断实践与优化,将使你在数据科学的工作中更加游刃有余。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闲人编程

你的鼓励就是我最大的动力,谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值