Нашли ошибку?
среднийpandas 3.0.6

Почему iterrows медленный

Чем плох перебор строк через iterrows и что использовать вместо него.

Нужно знать:Функции: map, apply, pipe

Содержание статьи

Коротко

  • iterrows() на каждой строке создаёт новый Series — это медленно.
  • Series хранит один тип, поэтому в строке целые превращаются в float, если рядом есть дробные.
  • itertuples() возвращает именованные кортежи: в несколько раз быстрее, типы сохраняются, поля — row.qty.
  • Для нескольких столбцов подходит zip(df["a"], df["b"]).
  • Лучший вариант — вообще без цикла: операции над столбцами, np.where, groupby, merge.
  • Изменения row внутри цикла не попадают в таблицу.

Синтаксис

for idx, row in df.iterrows(): ...        # медленно, типы теряются
for row in df.itertuples(index=False): row.col
for a, b in zip(df["a"], df["b"]): ...
df.to_dict("records")                      # список словарей
Задача в цикле Замена
новый столбец из других df["c"] = df["a"] * df["b"]
значение по условию np.where(cond, x, y), np.select
сумма / среднее по группам groupby(...).agg(...)
подставить данные из другой таблицы merge
накопленная сумма cumsum()

Примеры

Данные для примеровиспользуются во всех примерах ниже
import timeit

orders = pd.DataFrame({
    "item": ["латте", "чай", "раф"],
    "qty": [2, 1, 3],
    "price": [180.0, 90.0, 220.0],
})
iterrows
for idx, row in orders.iterrows():
    print(idx, row["item"], row["qty"] * row["price"])
Вывод
0 латте 360.0
1 чай 90.0
2 раф 660.0
itertuples — быстрее
for row in orders.itertuples(index=False):
    print(row.item, row.qty * row.price)       # быстрее и типы сохраняются
Вывод
латте 360.0
чай 90.0
раф 660.0
zip по столбцам
for item, qty in zip(orders["item"], orders["qty"]):
    print(item, qty)
Вывод
латте 2
чай 1
раф 3
Без цикла
orders["total"] = orders["qty"] * orders["price"]   # вместо цикла
orders
Вывод
    item  qty  price  total
0  латте    2  180.0  360.0
1    чай    1   90.0   90.0
2    раф    3  220.0  660.0
Если нужен обычный Python — to_dict
orders.to_dict("records")                      # список словарей — если нужен Python-код
Вывод
[{'item': 'латте', 'qty': 2, 'price': 180.0}, {'item': 'чай', 'qty': 1, 'price': 90.0}, {'item': 'раф', 'qty': 3, 'price': 220.0}]

Подводные камни

Типы в строке iterrows

Целое стало дробным
_, row = next(orders[["qty", "price"]].iterrows())
row                                            # qty стал float: строка — один Series одного типа
Вывод
qty        2.0
price    180.0
Name: 0, dtype: float64

Изменение row не меняет таблицу

row — копия данных строки. Меняйте таблицу через df.loc[idx, "col"] = …, а лучше — векторной операцией.

Запись в row
for _, row in orders.iterrows():
    row["qty"] = 0                             # меняется копия строки
orders["qty"].tolist()
Вывод
[2, 1, 3]

Скорость

iterrows, itertuples и векторная операция
big = pd.concat([orders] * 3000, ignore_index=True)   # 9000 строк
ways = {
    "iterrows": lambda: [r["qty"] * r["price"] for _, r in big.iterrows()],
    "itertuples": lambda: [r.qty * r.price for r in big.itertuples()],
    "векторно": lambda: big["qty"] * big["price"],
}
for name, f in ways.items():
    print(f"{name}: {min(timeit.repeat(f, number=1, repeat=3)) * 1000:.2f} мс")
Выводзамер на Apple M4 · macOS · Python 3.14, 29.09.2026
iterrows: 67.63 мс
itertuples: 4.58 мс
векторно: 0.03 мс

Время снято один раз и показано вместе с машиной и датой замера. На другом компьютере числа будут другими, но порядок разницы сохранится.