杰瑞科技汇

Python中.iterrows()如何高效遍历DataFrame行?

这是一个在数据分析中非常常用,但也需要谨慎使用的方法。

Python中.iterrows()如何高效遍历DataFrame行?-图1
(图片来源网络,侵删)

核心概念

.iterrows() 是 Pandas DataFrame 对象的一个方法,它的作用是逐行迭代一个 DataFrame,对于每一行,它会返回两个值:

  1. 行的索引 (index)
  2. 包含该行所有数据的 Pandas Series (a Pandas Series representing the data)

基本语法和用法

import pandas as pd
# 1. 创建一个示例 DataFrame
data = {
    'Name': ['Alice', 'Bob', 'Charlie', 'David'],
    'Age': [25, 30, 35, 28],
    'City': ['New York', 'Los Angeles', 'Chicago', 'Houston']
}
df = pd.DataFrame(data)
print("原始 DataFrame:")
print(df)
print("-" * 30)
# 2. 使用 iterrows() 进行迭代
print("使用 iterrows() 遍历 DataFrame:")
for index, row in df.iterrows():
    # index 是当前行的索引 (0, 1, 2, ...)
    # row 是一个 Pandas Series,包含了该行的所有数据
    print(f"行索引: {index}")
    print(f"行数据 (Series):\n{row}")
    print(f"访问特定列: 姓名={row['Name']}, 年龄={row['Age']}")
    print("-" * 20)

输出结果:

原始 DataFrame:
      Name  Age         City
0    Alice   25     New York
1      Bob   30  Los Angeles
2  Charlie   35      Chicago
3    David   28      Houston
------------------------------
使用 iterrows() 遍历 DataFrame:
行索引: 0
行数据 (Series):
Name      Alice
Age          25
City    New York
Name: 0, dtype: object
访问特定列: 姓名=Alice, 年龄=25
--------------------
行索引: 1
行数据 (Series):
Name        Bob
Age          30
City    Los Angeles
Name: 1, dtype: object
访问特定列: 姓名=Bob, 年龄=30
--------------------
行索引: 2
行数据 (Series):
Name      Charlie
Age            35
City      Chicago
Name: 2, dtype: object
访问特定列: 姓名=Charlie, 年龄=35
--------------------
行索引: 3
行数据 (Series):
Name      David
Age          28
City    Houston
Name: 3, dtype: object
访问特定列: 姓名=David, 年龄=28
--------------------

关键特点与重要注意事项

性能问题(最重要的注意事项)

.iterrows() 的性能非常差。在绝大多数情况下,它都不是遍历 DataFrame 的最佳方式。

  • 原因.iterrows() 为 DataFrame 的每一行都创建了一个新的 Pandas Series 对象,这个创建和销毁对象的过程会带来巨大的开销,尤其是在处理大型 DataFrame 时,会变得非常慢。
  • 替代方案:对于简单的逐行操作,或者需要修改 DataFrame 的值,强烈推荐使用 .itertuples(),它的速度要快得多(通常快几个数量级)。

数据类型问题

.iterrows() 返回的 row 是一个 Pandas Series,这意味着:

Python中.iterrows()如何高效遍历DataFrame行?-图2
(图片来源网络,侵删)
  • 列名成为 Series 的索引:你可以通过 row['列名']row.列名 来访问数据。
  • 数据类型会保留:Series 中的数据会保持其在 DataFrame 中原有的数据类型(如 int, str, float 等)。

这与 .itertuples() 返回一个命名元组不同,后者通常访问起来更快且更直观。


.iterrows() vs. .itertuples() (性能对比)

让我们通过一个简单的性能测试来直观感受它们的差异。

import pandas as pd
import time
# 创建一个更大的 DataFrame
df_large = pd.DataFrame({'A': range(100000), 'B': range(100000, 200000)})
# --- 测试 iterrows() ---
start_time = time.time()
for index, row in df_large.iterrows():
    # 做一些简单的操作
    _ = row['A'] + row['B']
iterrows_time = time.time() - start_time
print(f"iterrows() 耗时: {iterrows_time:.4f} 秒")
# --- 测试 itertuples() ---
start_time = time.time()
for row_tuple in df_large.itertuples():
    # 访问元组元素,速度更快
    _ = row_tuple.A + row_tuple.B
itertuples_time = time.time() - start_time
print(f"itertuples() 耗时: {itertuples_time:.4f} 秒")
# --- 测试向量化操作 (最佳实践) ---
start_time = time.time()
# 这是 Pandas 推荐的最高效的方式
_ = df_large['A'] + df_large['B']
vectorized_time = time.time() - start_time
print(f"向量化操作 耗时: {vectorized_time:.4f} 秒")

在我的机器上可能的输出:

iterrows() 耗时: 5.2341 秒
itertuples() 耗时: 0.0152 秒
向量化操作 耗时: 0.0010 秒

结论显而易见:

Python中.iterrows()如何高效遍历DataFrame行?-图3
(图片来源网络,侵删)
  • 向量化操作 > .itertuples() >> .iterrows()

何时应该使用 .iterrows()

尽管有性能问题,但在某些特定场景下,.iterrows() 仍然有其用武之地:

  1. 需要访问行索引和行数据:当你迭代时,同时需要知道当前行的索引(index)和该行的完整数据(row Series)时,.iterrows() 非常方便。.itertuples() 也可以通过 row_tuple.Index 获取索引,但不如 .iterrows() 直接。

  2. 逐行修改 DataFrame(不推荐,但可行): 你可以在循环中修改 Series 的值,然后将其赋回给 DataFrame。这通常也很慢,并且可能会引发 SettingWithCopyWarning 警告。

    for index, row in df.iterrows():
        if row['Age'] > 30:
            # 修改 'Age' 列的值
            df.at[index, 'Age'] = row['Age'] + 1
    print("\n修改后的 DataFrame:")
    print(df)

    输出:

    修改后的 DataFrame:
          Name  Age         City
    0      Alice   25     New York
    1        Bob   30  Los Angeles
    2    Charlie   36      Chicago
    3      David   28      Houston

    更好的做法:使用布尔索引进行向量化修改。

    # 更高效的方式
    df.loc[df['Age'] > 30, 'Age'] += 1
  3. 复杂的、逐行的逻辑:当你的操作逻辑非常复杂,无法用向量化操作(如 apply 或布尔索引)表示,且必须逐行处理时,.iterrows() 是一个可用的(尽管不是最高效的)选择。


总结与最佳实践

特性 .iterrows() .itertuples() 向量化操作
速度 最快
返回值 (index, Series) namedtuple SeriesDataFrame
访问数据 row['col']row.col row.col (更直观) df['col']
主要用途 需要索引和行数据 快速逐行迭代 首选,对列进行数学/逻辑运算
Pandas哲学 避免,仅在必要时使用 推荐的迭代方式 最高效的Pandas方式

黄金法则:

  1. 永远优先尝试使用向量化操作,这是 Pandas 的核心优势,也是性能最优的解决方案。df['A'] * df['B']df[df['A'] > 10]
  2. 如果必须逐行迭代,优先使用 .itertuples(),它在绝大多数情况下都比 .iterrows() 快得多,且足够方便。
  3. 只在极少数情况下才考虑使用 .iterrows(),例如你确实需要同时获取行索引和行 Series,并且性能不是瓶颈。

Pandas 的设计初衷就是为了避免像 Python 原生列表那样的逐行循环,而是利用底层的 NumPy 实现高效的向量化计算。

分享:
扫描分享到社交APP
上一篇
下一篇