Как перебирать строки в DataFrame в Pandas?

1954

У меня есть DataFrameот панды:

import pandas as pd
inp = [{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}]
df = pd.DataFrame(inp)
print df

Вывод:

   c1   c2
0  10  100
1  11  110
2  12  120

Теперь я хочу перебрать строки этого кадра. Для каждой строки я хочу иметь возможность доступа к ее элементам (значениям в ячейках) по имени столбцов. Например:

for row in df.rows:
   print row['c1'], row['c2']

Возможно ли это сделать в пандах?

Я нашел этот похожий вопрос . Но это не дает мне ответ, который мне нужен. Например, там предлагается использовать:

for date, row in df.T.iteritems():

или

for row in df.iterrows():

Но я не понимаю, что это за rowобъект и как я могу с ним работать.

Роман
источник
11
Функция df.iteritems () выполняет итерации по столбцам, а не по строкам. Таким образом, чтобы сделать итерацию по строкам, вы должны транспонировать («T»), что означает, что вы меняете строки и столбцы друг на друга (отражая по диагонали). В результате вы эффективно выполняете итерации исходного кадра данных по его строкам, когда используете df.T.iteritems ()
Стефан Грюнвальд,
12
Если вы новичок в этой теме и новичок в пандах, НЕ ИМЕЙТЕ! Итерации по фреймам данных - это анти-паттерн, и вы не должны этого делать, если не хотите привыкать к большим ожиданиям. В зависимости от того, что вы пытаетесь сделать, возможно , есть гораздо лучшие альтернативы . iter*функции следует использовать в очень редких случаях. Также связано .
cs95
19
В отличие от того, что говорит cs95, есть совершенно веские причины, чтобы перебирать кадры данных, поэтому новым пользователям не следует расстраиваться. Один пример - если вы хотите выполнить некоторый код, используя значения каждой строки в качестве входных данных. Кроме того, если ваш фрейм данных достаточно мал (например, менее 1000 элементов), производительность на самом деле не является проблемой.
oulenz
1
@oulenz: Если по какой-то странной причине вы хотите столкнуться с проблемой использования API в целях, для которых оно было разработано (высокопроизводительные преобразования данных), тогда будьте моим гостем. Но, по крайней мере, не используйте iterrows, есть лучшие способы перебора DataFrame, вы можете просто перебрать список списков на этом этапе. Если вы находитесь в точке, где вы ничего не делаете, кроме как перебираете DataFrames, использование DataFrame на самом деле не имеет никакой пользы (если вы перебираете его, это единственное, что вы делаете с ним). Просто мой 2с.
cs95
8
Я второй @oulenz. Насколько я могу судить, pandasэто выбор чтения файла CSV, даже если набор данных небольшой. Программировать данные проще с помощью API-интерфейсов
Chris

Ответы:

2640

DataFrame.iterrows - это генератор, который выдает как индекс, так и строку

import pandas as pd
import numpy as np

df = pd.DataFrame([{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}])

for index, row in df.iterrows():
    print(row['c1'], row['c2'])

Output: 
   10 100
   11 110
   12 120
waitingkuo
источник
207
Примечание: «Поскольку iterrows возвращает Series для каждой строки, он не сохраняет dtypes в строках». Кроме того, «Вы никогда не должны изменять то, что вы повторяете». Согласно пандам 0.19.1 документов
viddik13
3
@ viddik13 это большое замечание, спасибо. Из-за этого я натолкнулся на случай, когда числовые значения, например, 431341610650читаются как 4.31E+11. Есть ли способ сохранить dtypes?
Азиз Альто
26
@AzizAlto использовать itertuples, как описано ниже. См. Также pandas.pydata.org/pandas-docs/stable/generated/…
Аксель
101
Не используйте iterrows. Itertuples быстрее и сохраняет тип данных. Больше информации
Джеймс Л.
11
Из документации : «Итерация по объектам pandas, как правило, медленная. Во многих случаях итерация по строкам вручную не требуется [...]». Ваш ответ правильный (в контексте вопроса), но нигде не упоминает об этом, поэтому он не очень хороший.
cs95
465

Как перебирать строки в DataFrame в Pandas?

Ответ: НЕ * !

Итерации в пандах - это анти-паттерн, и вы должны делать это только тогда, когда исчерпали все остальные опции. Вы не должны использовать какую-либо функцию с " iter" в названии более нескольких тысяч строк, иначе вам придется привыкнуть к большим ожиданиям.

Хотите распечатать DataFrame? Использование DataFrame.to_string().

Вы хотите что-то вычислить? В этом случае ищите методы в следующем порядке (список изменен здесь ):

  1. Векторизация
  2. Подпрограммы Cython
  3. Список Пониманий (ванильная forпетля)
  4. DataFrame.apply(): i) Сокращения, которые могут быть выполнены в Cython, II) Итерация в пространстве Python
  5. DataFrame.itertuples() а также iteritems()
  6. DataFrame.iterrows()

iterrowsи itertuples(оба получают много голосов в ответах на этот вопрос) следует использовать в очень редких случаях, таких как создание объектов строк / именных кортежей для последовательной обработки, что на самом деле является единственной вещью, для которой эти функции полезны.

Обращение к власти
На странице документации по итерации есть огромное красное окно с предупреждением:

Итерация по объектам панд обычно медленная. Во многих случаях повторение вручную по строкам не требуется [...].

* Это на самом деле немного сложнее, чем «нет». df.iterrows()это правильный ответ на этот вопрос, но «векторизация ваших операций» лучше. Я признаю, что существуют обстоятельства, в которых нельзя избежать итерации (например, некоторые операции, в которых результат зависит от значения, вычисленного для предыдущей строки). Однако для того, чтобы узнать, когда это нужно, нужно некоторое знакомство с библиотекой. Если вы не уверены, нужно ли вам итеративное решение, скорее всего, нет. PS: Чтобы узнать больше о моем обосновании написания этого ответа, перейдите к самому низу.


Быстрее, чем зацикливание: векторизация , Cython

Большое количество базовых операций и вычислений "векторизовано" пандами (либо через NumPy, либо через функции Cythonized). Это включает в себя арифметику, сравнения, (большинство) сокращений, изменение формы (например, поворот), объединений и групповых операций. Просмотрите документацию по основным функциям, чтобы найти подходящий векторизованный метод для вашей проблемы.

Если ничего не существует, не стесняйтесь писать свои собственные, используя собственные расширения Cython .


Следующая лучшая вещь: список понимания *

Следующее понимание списка должно быть вашим следующим портом захода, если 1) нет доступного векторизованного решения, 2) производительность важна, но недостаточно важна для того, чтобы пройти через процесс кефонизации вашего кода, и 3) вы пытаетесь выполнить поэлементное преобразование в вашем коде. Существует множество доказательств того, что составление списков является достаточно быстрым (и даже иногда более быстрым) для многих обычных задач панд.

Формула проста,

# iterating over one column - `f` is some function that processes your data
result = [f(x) for x in df['col']]
# iterating over two columns, use `zip`
result = [f(x, y) for x, y in zip(df['col1'], df['col2'])]
# iterating over multiple columns - same data type
result = [f(row[0], ..., row[n]) for row in df[['col1', ...,'coln']].to_numpy()]
# iterating over multiple columns - differing data type
result = [f(row[0], ..., row[n]) for row in zip(df['col1'], ..., df['coln'])]

Если вы можете инкапсулировать свою бизнес-логику в функцию, вы можете использовать понимание списка, которое ее вызывает. Вы можете заставить произвольно сложные вещи работать благодаря простоте и скорости необработанного Python.

Понятия Caveats
List предполагают, что с вашими данными легко работать - это означает, что ваши типы данных согласованы и у вас нет NaN, но это не всегда может быть гарантировано.

  1. Первый более очевиден, но при работе с NaN предпочтите встроенные методы панд, если они существуют (потому что они имеют гораздо лучшую логику обработки угловых случаев), или убедитесь, что ваша бизнес-логика включает соответствующую логику обработки NaN.
  2. При работе со смешанными типами данных вы должны выполнять итерацию zip(df['A'], df['B'], ...)вместо того, df[['A', 'B']].to_numpy()чтобы последний неявно преобразовывал данные в наиболее распространенный тип. Например, если A числовое, а B строковое, to_numpy()приведёт весь массив к строковому, что может быть не тем, что вы хотите. К счастью, zipобъединить ваши столбцы - это самый простой обходной путь.

* YMMV по причинам, изложенным в разделе « Предостережения » выше.


Очевидный пример

Продемонстрируем разницу на простом примере добавления двух столбцов панд A + B. Это векторизованный оперон, поэтому будет легко сравнить производительность методов, описанных выше.

Код для сравнения, для вашей справки. Линия внизу измеряет функцию, написанную на numpandas, стиле панд, который сильно смешивается с numpy, чтобы выжать максимальную производительность. Написание кода numpandas следует избегать, если вы не знаете, что делаете. Придерживайтесь API, где вы можете (то есть, предпочитаете vecболее vec_numpy).

Я должен отметить, однако, что это не всегда так сухо. Иногда ответ «что является лучшим методом для операции» - «это зависит от ваших данных». Мой совет, чтобы проверить различные подходы к вашим данным, прежде чем остановиться на одном.


Дальнейшее чтение

* Строковые методы панд "векторизованы" в том смысле, что они указаны в серии, но работают с каждым элементом. Базовые механизмы все еще итеративны, потому что строковые операции по своей природе трудно векторизовать.


Почему я написал этот ответ

Обычная тенденция, которую я замечаю у новых пользователей, - это задавать вопросы в форме «как я могу перебрать свой df, чтобы сделать X?». Отображение кода, вызывающего iterrows()при выполнении чего-либо внутри цикла for. Вот почему. Новый пользователь библиотеки, который не был ознакомлен с концепцией векторизации, скорее всего, представит код, который решает их проблему, как перебирая свои данные, чтобы что-то сделать. Не зная, как перебирать DataFrame, первое, что они делают, - это Google и в конечном итоге здесь, на этот вопрос. Затем они видят принятый ответ, говорящий им, как это сделать, и закрывают глаза и запускают этот код, даже не задавая вопрос, является ли итерация неправильной вещью.

Цель этого ответа состоит в том, чтобы помочь новым пользователям понять, что итерация не обязательно является решением каждой проблемы, и что могут существовать лучшие, более быстрые и более идиоматические решения, и что стоит потратить время на их изучение. Я не пытаюсь начать войну итераций против векторизации, но я хочу, чтобы новые пользователи были информированы при разработке решений своих проблем с этой библиотекой.

cs95
источник
24
Это единственный ответ, который фокусируется на идиоматических техниках, которые следует использовать с пандами, что делает его лучшим ответом на этот вопрос. Обучение правильному ответу с правильным кодом (вместо правильного ответа с неправильным кодом - т.е. неэффективным, не масштабируемым, слишком подходящим для конкретных данных) является большой частью изучения панд (и данных в целом).
LinkBerest
3
Я думаю, что вы несправедливы по отношению к циклу for, хотя, видя, что они только немного медленнее, чем понимание списков в моих тестах. Хитрость в том, чтобы перебрать zip(df['A'], df['B'])вместо df.iterrows().
Нетленная ночь
2
@ImperishableNight Совсем нет; смысл этого поста не в том, чтобы осудить итерацию в целом, а в том, чтобы конкретно осудить использование iterrows()и неявно осудить итерацию, если и когда существуют лучшие альтернативы. forсами по себе циклы в порядке, но списки лучше, если вы итеративно выполняете поэлементные преобразования.
CS95
1
@sdbbs, используйте sort_values ​​для сортировки данных, затем вызовите to_string () для результата.
cs95
1
В разделе «Понимание списка» для примера «итерации по нескольким столбцам» требуется предупреждение: DataFrame.valuesкаждый столбец будет преобразован в общий тип данных. DataFrame.to_numpy()делает это тоже. К счастью, мы можем использовать zipлюбое количество столбцов.
Дэвид Вассерман
398

Сначала подумайте, действительно ли вам нужно перебирать строки в DataFrame. Смотрите этот ответ для альтернатив.

Если вам все еще нужно перебирать строки, вы можете использовать методы ниже. Обратите внимание на некоторые важные предостережения, которые не упоминаются ни в одном из других ответов.

itertuples() должен быть быстрее чем iterrows()

Но имейте в виду, согласно документам (панды 0.24.2 на данный момент):

  • iterrows: dtype может не совпадать от строки к строке

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

  • iterrows: не изменять строки

    Вам следует никогда не изменять то, что вы повторяете. Это не гарантирует работу во всех случаях. В зависимости от типов данных итератор возвращает копию, а не представление, и запись в него не будет иметь никакого эффекта.

    Вместо этого используйте DataFrame.apply () :

    new_df = df.apply(lambda x: x * 2)
  • itertuples:

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

Смотрите pandas docs на итерации для более подробной информации.

viddik13
источник
4
Просто небольшой вопрос от того, кто читает эту ветку так долго после ее завершения: как df.apply () сравнивается с itertuples с точки зрения эффективности?
Рауль Гуарини
4
Примечание: вы также можете сказать что-то вроде for row in df[['c1','c2']].itertuples(index=True, name=None):включения только определенных столбцов в итератор строк.
Брайан Бернс
12
Вместо getattr(row, "c1"), вы можете использовать только row.c1.
Вираптор
1
Я на 90% уверен, что если вы используете getattr(row, "c1")вместо этого row.c1, вы потеряете любое преимущество в производительности itertuples, и если вам действительно нужно получить свойство через строку, вы должны использовать вместо него iterrows.
Ноктофобия
3
Я наткнулся на этот вопрос, потому что, хотя я знал, что есть split-apply- Объединить , мне все же действительно нужно было перебрать DataFrame (как говорится в вопросе). Не у всех есть такая роскошь, которую можно улучшить, numbaи cython(одни и те же документы говорят, что «в Python всегда стоит оптимизировать в первую очередь»). Я написал этот ответ, чтобы помочь другим избежать (иногда расстраивающих) проблем, поскольку ни один из других ответов не упоминает эти предостережения. Вводить кого-либо в заблуждение или говорить «это правильно» никогда не было моим намерением. Я улучшил ответ.
viddik13
201

Вы должны использовать df.iterrows(). Хотя итерация строка за строкой не особенно эффективна, так как Seriesобъекты должны быть созданы.

Уэс МакКинни
источник
12
Это быстрее, чем преобразование DataFrame в пустой массив (через .values) и непосредственная работа с массивом? У меня та же проблема, но в конечном итоге преобразовать в массив Numpy, а затем с помощью Cython.
vgoklani
12
@vgoklani Если итерация строка-за-строкой неэффективна и у вас есть необъектный массив numpy, то почти наверняка использование необработанного numpy массива будет быстрее, особенно для массивов с большим количеством строк. вам следует избегать итерации по строкам, если только вам это не нужно
Филлип Облако
7
Я провел небольшое тестирование на потребление времени для df.iterrows (), df.itertuples () и zip (df ['a'], df ['b']) и опубликовал результат в ответе другого вопрос: stackoverflow.com/a/34311080/2142098
Ричард Вонг
154

Хотя iterrows()это хороший вариант, иногда itertuples()может быть гораздо быстрее:

df = pd.DataFrame({'a': randn(1000), 'b': randn(1000),'N': randint(100, 1000, (1000)), 'x': 'x'})

%timeit [row.a * 2 for idx, row in df.iterrows()]
# => 10 loops, best of 3: 50.3 ms per loop

%timeit [row[1] * 2 for row in df.itertuples()]
# => 1000 loops, best of 3: 541 µs per loop
e9t
источник
5
Большая часть разницы во времени в ваших двух примерах выглядит так, как будто вы используете индексирование на основе меток для команды .iterrows () и целочисленное индексирование для команды .itertuples ().
Алекс
2
Для фрейма данных, основанного на финансовых данных (timestamp и 4x float), itertuples в 19,57 раза быстрее, чем iterrows на моей машине. Только for a,b,c in izip(df["a"],df["b"],df["c"]:почти одинаково быстро.
Harbun
7
Можете ли вы объяснить, почему это быстрее?
Абэ Мисслер
4
@AbeMiessler упаковывает iterrows()каждую строку данных в Серию, а itertuples()не делает.
Мирадуло
3
Обратите внимание, что порядок столбцов на самом деле является неопределенным, поскольку dfсоздается из словаря, поэтому row[1]может ссылаться на любой из столбцов. Как оказалось, время примерно одинаковое для целого числа и столбцов с плавающей точкой.
Брайан Бернс
88

Вы также можете использовать df.apply()для перебора строк и доступа к нескольким столбцам для функции.

документы: DataFrame.apply ()

def valuation_formula(x, y):
    return x * y * 0.5

df['price'] = df.apply(lambda row: valuation_formula(row['x'], row['y']), axis=1)
нахальный ублюдок
источник
Является ли df ['price'] ссылкой на имя столбца во фрейме данных? Я пытаюсь создать словарь с уникальными значениями из нескольких столбцов в CSV-файле. Я использовал вашу логику для создания словаря с уникальными ключами и значениями и получил сообщение об ошибке TypeError: («Объекты 'Series' являются изменяемыми, поэтому их нельзя хэшировать", u'прибыли по индексу 0 ")
SRS
Код: df ['Workclass'] = df.apply (лямбда-строка: dic_update (row), axis = 1) конец строки id = 0 конец строки def dic_update (row): если строка не в dic: dic [row] = id id = id + 1
SRS
Неважно, я понял. Изменена строка вызова функции на df_new = df ['Workclass']. Apply (то же самое)
SRS
2
Наименьшее
9
Обратите внимание, что applyон не «повторяется» над строками, скорее он применяет функцию по строкам. Приведенный выше код не будет не работать , если вы действительно делаете итерации нужна , и индексы, например , при сравнении значений в разных строках (в этом случае вы можете сделать ничего , кроме итерацию).
gented
82

Вы можете использовать функцию df.iloc следующим образом:

for i in range(0, len(df)):
    print df.iloc[i]['c1'], df.iloc[i]['c2']
PJay
источник
1
Я знаю, что этого следует избегать в пользу iterrows или itertuples, но было бы интересно узнать почему. Какие-нибудь мысли?
rocarvaj
12
Это единственный действительный метод, который я знаю, если вы хотите сохранить типы данных, а также ссылаться на столбцы по имени. itertuplesсохраняет типы данных, но избавляется от любого имени, которое ему не нравится. iterrowsделает обратное.
Кен Уильямс
6
Потратил часы, пытаясь пробираться через особенности структур данных панд, чтобы сделать что-то простое и выразительное. Это приводит к читабельности кода.
Шон Андерсон
Хотя это for i in range(df.shape[0])может немного ускорить этот подход, он все равно примерно в 3,5 раза медленнее, чем описанный выше подход iterrows () для моего приложения.
Ким Миллер
На больших Datafrmes это выглядит лучше, так как my_iter = df.itertuples()занимает вдвое больше памяти и много времени для ее копирования. то же самое для iterrows().
Бастиан
33

Я искал Как перебирать строки и столбцы и закончил вот так:

for i, row in df.iterrows():
    for j, column in row.iteritems():
        print(column)
Лукас Б
источник
18

Вы можете написать свой собственный итератор, который реализует namedtuple

from collections import namedtuple

def myiter(d, cols=None):
    if cols is None:
        v = d.values.tolist()
        cols = d.columns.values.tolist()
    else:
        j = [d.columns.get_loc(c) for c in cols]
        v = d.values[:, j].tolist()

    n = namedtuple('MyTuple', cols)

    for line in iter(v):
        yield n(*line)

Это прямо сопоставимо с pd.DataFrame.itertuples. Я стремлюсь выполнить ту же задачу с большей эффективностью.


Для данного кадра данных с моей функцией:

list(myiter(df))

[MyTuple(c1=10, c2=100), MyTuple(c1=11, c2=110), MyTuple(c1=12, c2=120)]

Или с pd.DataFrame.itertuples:

list(df.itertuples(index=False))

[Pandas(c1=10, c2=100), Pandas(c1=11, c2=110), Pandas(c1=12, c2=120)]

Комплексный тест
Мы тестируем доступность всех столбцов и подмножество столбцов.

def iterfullA(d):
    return list(myiter(d))

def iterfullB(d):
    return list(d.itertuples(index=False))

def itersubA(d):
    return list(myiter(d, ['col3', 'col4', 'col5', 'col6', 'col7']))

def itersubB(d):
    return list(d[['col3', 'col4', 'col5', 'col6', 'col7']].itertuples(index=False))

res = pd.DataFrame(
    index=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
    columns='iterfullA iterfullB itersubA itersubB'.split(),
    dtype=float
)

for i in res.index:
    d = pd.DataFrame(np.random.randint(10, size=(i, 10))).add_prefix('col')
    for j in res.columns:
        stmt = '{}(d)'.format(j)
        setp = 'from __main__ import d, {}'.format(j)
        res.at[i, j] = timeit(stmt, setp, number=100)

res.groupby(res.columns.str[4:-1], axis=1).plot(loglog=True);

введите описание изображения здесь

введите описание изображения здесь

piRSquared
источник
2
Для людей, которые не хотят читать код: синяя линия означает intertuples, что оранжевая линия - это список итераторов в блоке yield. interrowsне сравнивается.
Джеймс Л.
18

Как эффективно выполнять итерации?

Если вам действительно нужно итерировать кадр данных pandas, вы, вероятно, захотите избегать использования iterrows () . Существуют разные методы, и обычный iterrows()далеко не самый лучший. itertuples () может быть в 100 раз быстрее.

Короче говоря:

  • Как правило, используйте df.itertuples(name=None). В частности, когда у вас фиксированное число столбцов и менее 255 столбцов. Смотрите пункт (3)
  • В противном случае используйте, df.itertuples()кроме случаев, когда в ваших столбцах есть специальные символы, такие как пробелы или '-'. Смотрите пункт (2)
  • Это можно использовать, itertuples()даже если ваш фрейм данных имеет странные столбцы, используя последний пример. Смотрите пункт (4)
  • Используйте только iterrows()если вы не можете предыдущие решения. Смотрите пункт (1)

Различные методы итерации по строкам в фрейме данных pandas:

Создайте случайный кадр данных с миллионом строк и 4 столбцами:

    df = pd.DataFrame(np.random.randint(0, 100, size=(1000000, 4)), columns=list('ABCD'))
    print(df)

1) Обычное iterrows()удобно, но чертовски медленно:

start_time = time.clock()
result = 0
for _, row in df.iterrows():
    result += max(row['B'], row['C'])

total_elapsed_time = round(time.clock() - start_time, 2)
print("1. Iterrows done in {} seconds, result = {}".format(total_elapsed_time, result))

2) По умолчанию itertuples()уже намного быстрее, но он не работает с именами столбцов, такими как My Col-Name is very Strange(вы должны избегать этого метода, если ваши столбцы повторяются или если имя столбца не может быть просто преобразовано в имя переменной Python) .:

start_time = time.clock()
result = 0
for row in df.itertuples(index=False):
    result += max(row.B, row.C)

total_elapsed_time = round(time.clock() - start_time, 2)
print("2. Named Itertuples done in {} seconds, result = {}".format(total_elapsed_time, result))

3) Использование по умолчанию itertuples()name = None еще быстрее, но не очень удобно, поскольку вы должны определить переменную для каждого столбца.

start_time = time.clock()
result = 0
for(_, col1, col2, col3, col4) in df.itertuples(name=None):
    result += max(col2, col3)

total_elapsed_time = round(time.clock() - start_time, 2)
print("3. Itertuples done in {} seconds, result = {}".format(total_elapsed_time, result))

4) Наконец, named itertuples()медленнее, чем предыдущая точка, но вам не нужно определять переменную для каждого столбца, и он работает с именами столбцов, такими как My Col-Name is very Strange.

start_time = time.clock()
result = 0
for row in df.itertuples(index=False):
    result += max(row[df.columns.get_loc('B')], row[df.columns.get_loc('C')])

total_elapsed_time = round(time.clock() - start_time, 2)
print("4. Polyvalent Itertuples working even with special characters in the column name done in {} seconds, result = {}".format(total_elapsed_time, result))

Вывод:

         A   B   C   D
0       41  63  42  23
1       54   9  24  65
2       15  34  10   9
3       39  94  82  97
4        4  88  79  54
...     ..  ..  ..  ..
999995  48  27   4  25
999996  16  51  34  28
999997   1  39  61  14
999998  66  51  27  70
999999  51  53  47  99

[1000000 rows x 4 columns]

1. Iterrows done in 104.96 seconds, result = 66151519
2. Named Itertuples done in 1.26 seconds, result = 66151519
3. Itertuples done in 0.94 seconds, result = 66151519
4. Polyvalent Itertuples working even with special characters in the column name done in 2.94 seconds, result = 66151519

Эта статья представляет собой очень интересное сравнение между iterrows и itertuples

Ромен Капрон
источник
14

Чтобы зациклить все строки в dataframeвы можете использовать:

for x in range(len(date_example.index)):
    print date_example['Date'].iloc[x]
CONvid19
источник
1
Это цепная индексация. Я не рекомендую делать это.
cs95
@ cs95 Что бы вы порекомендовали вместо этого?
CONvid19
Если вы хотите, чтобы это работало, вызовите df.columns.get_loc, чтобы получить целочисленную позицию индекса столбца даты (вне цикла), а затем используйте один вызов индекса iloc внутри.
cs95
14
 for ind in df.index:
     print df['c1'][ind], df['c2'][ind]
Grag2015
источник
1
Какова производительность этой опции при использовании на большом фрейме данных (например, миллионы строк)?
Базили Дебовски
Честно говоря, я не знаю точно, я думаю, что по сравнению с лучшим ответом прошедшее время будет примерно одинаковым, потому что в обоих случаях используется конструкция "for". Но память может отличаться в некоторых случаях.
Grag2015
4
Это цепная индексация. Не используйте это!
cs95
7

Иногда полезный шаблон:

# Borrowing @KutalmisB df example
df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]}, index=['a', 'b'])
# The to_dict call results in a list of dicts
# where each row_dict is a dictionary with k:v pairs of columns:value for that row
for row_dict in df.to_dict(orient='records'):
    print(row_dict)

Что приводит к:

{'col1':1.0, 'col2':0.1}
{'col1':2.0, 'col2':0.2}
Zach
источник
6

Чтобы зациклить все строки в a dataframeи удобно использовать значения каждой строки , их можно преобразовать в s. Например:namedtuplesndarray

df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]}, index=['a', 'b'])

Итерация по строкам:

for row in df.itertuples(index=False, name='Pandas'):
    print np.asarray(row)

результаты в:

[ 1.   0.1]
[ 2.   0.2]

Обратите внимание , что если index=True, индекс добавляется в качестве первого элемента кортежа , который может быть нежелательным для некоторых применений.

Инженер герпеса
источник
5

Существует способ перебрасывать строки броска при получении взамен DataFrame, а не Series. Я не вижу никого, кто упомянул бы, что вы можете передать index в виде списка для строки, которая будет возвращена как DataFrame:

for i in range(len(df)):
    row = df.iloc[[i]]

Обратите внимание на использование двойных скобок. Это возвращает DataFrame с одной строкой.

дух времени
источник
Это было очень полезно для получения n-й по величине строки во фрейме данных после сортировки. Спасибо!
Джейсон Харрисон
3

Для просмотра и изменения значений я бы использовал iterrows(). В цикле for и с помощью распаковки кортежей (см. Пример:) i, rowя использую rowтолько для просмотра значения и использования iс locметодом, когда я хочу изменить значения. Как указано в предыдущих ответах, здесь вы не должны изменять то, что вы повторяете.

for i, row in df.iterrows():
    df_column_A = df.loc[i, 'A']
    if df_column_A == 'Old_Value':
        df_column_A = 'New_value'  

Здесь rowв цикле есть копия этой строки, а не ее представление. Таким образом, вы не должны писать что-то вроде row['A'] = 'New_Value', это не будет изменять DataFrame. Тем не менее, вы можете использовать iи locи указать DataFrame для выполнения работы.

Хоссейн
источник
2

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

Я хотел бы добавить, что если вы сначала преобразуете фрейм данных в массив numpy, а затем используете векторизацию, это даже быстрее, чем векторизация пандасов фреймов данных (и это включает время, чтобы превратить его обратно в серию фреймов данных).

Если вы добавите следующие функции в тестовый код @ cs95, это станет довольно очевидным:

def np_vectorization(df):
    np_arr = df.to_numpy()
    return pd.Series(np_arr[:,0] + np_arr[:,1], index=df.index)

def just_np_vectorization(df):
    np_arr = df.to_numpy()
    return np_arr[:,0] + np_arr[:,1]

введите описание изображения здесь

средство от насекомых
источник
1

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

subset = row['c1'][0:5]
all = row['c1'][:]

Вы также можете привести его к массиву. Предполагается, что эти индексы / выборки уже действуют как массивы Numpy, но я столкнулся с проблемами и должен был разыграть

np.asarray(all)
imgs[:] = cv2.resize(imgs[:], (224,224) ) #resize every image in an hdf5 file
Джеймс Л.
источник
1

Существует много способов перебора строк в панде. Один очень простой и интуитивно понятный способ:

df=pd.DataFrame({'A':[1,2,3], 'B':[4,5,6],'C':[7,8,9]})
print(df)
for i in range(df.shape[0]):
    # For printing the second column
    print(df.iloc[i,1])
    # For printing more than one columns
    print(df.iloc[i,[0,2]])
Шубхам Ранджан
источник
0

В этом примере iloc используется для выделения каждой цифры в кадре данных.

import pandas as pd

 a = [1, 2, 3, 4]
 b = [5, 6, 7, 8]

 mjr = pd.DataFrame({'a':a, 'b':b})

 size = mjr.shape

 for i in range(size[0]):
     for j in range(size[1]):
         print(mjr.iloc[i, j])
mjr2000
источник
0

Некоторые библиотеки (например, библиотека взаимодействия Java, которую я использую) требуют, чтобы значения передавались подряд по очереди, например, при потоковой передаче данных. Чтобы воспроизвести потоковую природу, я «поочередно» перенаправляю значения своих данных в рамку, я написал ниже, что время от времени пригодится.

class DataFrameReader:
  def __init__(self, df):
    self._df = df
    self._row = None
    self._columns = df.columns.tolist()
    self.reset()
    self.row_index = 0

  def __getattr__(self, key):
    return self.__getitem__(key)

  def read(self) -> bool:
    self._row = next(self._iterator, None)
    self.row_index += 1
    return self._row is not None

  def columns(self):
    return self._columns

  def reset(self) -> None:
    self._iterator = self._df.itertuples()

  def get_index(self):
    return self._row[0]

  def index(self):
    return self._row[0]

  def to_dict(self, columns: List[str] = None):
    return self.row(columns=columns)

  def tolist(self, cols) -> List[object]:
    return [self.__getitem__(c) for c in cols]

  def row(self, columns: List[str] = None) -> Dict[str, object]:
    cols = set(self._columns if columns is None else columns)
    return {c : self.__getitem__(c) for c in self._columns if c in cols}

  def __getitem__(self, key) -> object:
    # the df index of the row is at index 0
    try:
        if type(key) is list:
            ix = [self._columns.index(key) + 1 for k in key]
        else:
            ix = self._columns.index(key) + 1
        return self._row[ix]
    except BaseException as e:
        return None

  def __next__(self) -> 'DataFrameReader':
    if self.read():
        return self
    else:
        raise StopIteration

  def __iter__(self) -> 'DataFrameReader':
    return self

Который может быть использован:

for row in DataFrameReader(df):
  print(row.my_column_name)
  print(row.to_dict())
  print(row['my_column_name'])
  print(row.tolist())

И сохраняет сопоставление значений / имен для итерируемых строк. Очевидно, это намного медленнее, чем использовать apply и Cython, как указано выше, но это необходимо в некоторых обстоятельствах.

Морганикс
источник
0

Короче говоря

  • Используйте векторизацию, если это возможно
  • Если операция не может быть векторизована - используйте списки
  • Если вам нужен один объект, представляющий всю строку - используйте itertuples
  • Если вышеупомянутое слишком медленно - попробуйте swifter.apply
  • Если это все еще слишком медленно - попробуйте рутину Cython

Подробности в этом видео

эталонный тест Тест итерации по строкам в панде DataFrame

artoby
источник