Коротко
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],
})for idx, row in orders.iterrows():
print(idx, row["item"], row["qty"] * row["price"])Вывод
0 латте 360.0 1 чай 90.0 2 раф 660.0
for row in orders.itertuples(index=False):
print(row.item, row.qty * row.price) # быстрее и типы сохраняютсяВывод
латте 360.0 чай 90.0 раф 660.0
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
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"] = …, а лучше — векторной операцией.
for _, row in orders.iterrows():
row["qty"] = 0 # меняется копия строки
orders["qty"].tolist()Вывод
[2, 1, 3]
Скорость
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 мс
Время снято один раз и показано вместе с машиной и датой замера. На другом компьютере числа будут другими, но порядок разницы сохранится.