Сообщить об ошибке.

Методы итерации по объектам pandas в Python

Поведение базовой итерации по объектам pandas зависит от типа. При итерации по Series, он рассматривается как массив, и базовая итерация создает значения. DataFrame следуют соглашению о переборе "ключей" объектов.

Короче говоря, итерация for i in object: по объекту:

  • Series: возвращает значения;
  • DataFrame: возвращает метки/имена столбцов.

Так, например, итерация по DataFrame дает имена столбцов:

import pandas as pd
import numpy as np

df = pd.DataFrame(
    {"col1": np.random.randn(3), "col2": np.random.randn(3)}, index=["a", "b", "c"]
)

for col in df:
    print(col)

# col1
# col2

Объекты pandas также имеют метод .Items(), похожий на dict.Items(), для перебора пар (key, value).

Для итерации по строкам DataFrame можно использовать следующие методы:

  • DataFrame.iterrows(): перебирает строки DataFrame как пары (index, Series). При этом строки преобразуются в объекты Series, что может изменить dtypes и имеет некоторые последствия для производительности.
  • DataFrame.itertuples(): перебирает строки DataFrame в виде именованных кортежей значений. Это намного быстрее, чем DataFrame.iterrows(), и в большинстве случаев предпочтительнее использовать для перебора значений DataFrame.

Предупреждение. Итерация по объектам pandas, как правило, выполняется медленно. Во многих случаях итерация вручную по строкам не требуется, и ее можно избежать с помощью одного из следующих подходов:

  • Ищите векторизованное решение: многие операции можно выполнять с помощью встроенных методов или функций NumPy, (логической) индексации, и т.д.
  • Если есть функция, которая не может работать со всем DataFrame/Series сразу, лучше использовать методы .apply() или .map() вместо итерации по значениям.

Предупреждение. В зависимости от типов данных, итератор возвращает копию, а не представление, и запись в него не будет иметь никакого эффекта! НЕ изменяйте объект итерации. Не гарантируется, что это сработает во всех случаях.

Например, в следующем случае установка значения не имеет никакого эффекта:

df = pd.DataFrame({"a": [1, 2, 3], "b": ["a", "b", "c"]})
for index, row in df.iterrows():
    row["a"] = 10

>>> df
#    a  b
# 0  1  a
# 1  2  b
# 2  3  c

Метод .items()

В соответствии с dict-подобным интерфейсом, метод dict.items() выполняет итерацию по парам ключ-значение:

  • Series.items() возвращает пары (index, value);
  • DataFrame.items() возвращает пары (column, Series).
>>> df = pd.DataFrame({"a": [1, 2, 3], "b": ["a", "b", "c"]})
>>> for label, ser in df.items():
...     print('label =>', label)
...     print(ser)
... 
# label => a
# 0    1
# 1    2
# 2    3
# Name: a, dtype: int64
# label => b
# 0    a
# 1    b
# 2    c
# Name: b, dtype: object

Метод DataFrame.iterrows()

Метод DataFrame.iterrows() позволяет выполнять итерацию по строкам DataFrame как по объектам Series. Он возвращает итератор, возвращающий каждое значение индекса вместе с Series, содержащим данные в каждой строке:

>>> df = pd.DataFrame({"a": [1, 2, 3], "b": ["a", "b", "c"]})
>>> for row_index, row in df.iterrows():
...     print(f'Индекс строки: {row_index}', row, sep="\n")
... 
# Индекс строки: 0
# a    1
# b    a
# Name: 0, dtype: object
# Индекс строки: 1
# a    2
# b    b
# Name: 1, dtype: object
# Индекс строки: 2
# a    3
# b    c
# Name: 2, dtype: object

Примечание Так как DataFrame.iterrows() возвращает Series для каждой строки, он не сохраняет dtypes в строках (dtypes сохраняются в столбцах для DataFrames). Например:

>>> df_orig = pd.DataFrame([[1, 1.5]], columns=["int", "float"])
>>> df_orig.dtypes
# int        int64
# float    float64
# dtype: object
>>> row = next(df_orig.iterrows())[1]
>>> row
# int      1.0
# float    1.5
# Name: 0, dtype: float64

Все значения в строке, возвращаемые в виде Series, теперь приводятся к числам с плавающей запятой, а также исходному целочисленному значению в столбце x:

>>> row["int"].dtype
# dtype('float64')
>>> df_orig["int"].dtype
# dtype('int64')

Чтобы сохранить dtypes при переборе строк, лучше использовать DataFrame.itertuples(), который возвращает именованные кортежи значений и который, как правило, намного быстрее, чем DataFrame.iterrows().

Метод DataFrame.itertuples()

Метод DataFrame.itertuples() вернет итератор, возвращающий именованный кортеж для каждой строки в DataFrame. Первым элементом кортежа будет соответствующее значение индекса строки, а остальные значения - значения строки.

Например:

>>> df = pd.DataFrame({"a": [1, 2, 3], "b": ["a", "b", "c"]})
>>> for row in df.itertuples():
...     print(row)
... 
# Pandas(Index=0, a=1, b='a')
# Pandas(Index=1, a=2, b='b')
# Pandas(Index=2, a=3, b='c')

Этот метод не преобразует строку в объект Series, он просто возвращает значения внутри именованного кортежа. Таким образом, DataFrame.itertuples() сохраняет тип данных значений и, как правило, работает быстрее, чем DataFrame.iterrows().

Заметка. Если имена столбцов не являются допустимыми идентификаторами Python, то они будут переименованы в позиционные имена. При большом количестве столбцов (>255) возвращаются обычные кортежи.