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

avatar
Roman
10 мая 2013 в 07:04
4374034
32
3035

У меня есть DataFrame от Pandas:

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']

Можно ли это сделать в Pandas?

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

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

или

for row in df.iterrows():

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

Источник
Stefan Gruenwald
14 декабря 2017 в 23:41
19

Df.iteritems () выполняет итерацию по столбцам, а не по строкам. Таким образом, чтобы заставить его перебирать строки, вы должны транспонировать («T»), что означает, что вы меняете строки и столбцы друг в друга (отражаете по диагонали). В результате вы эффективно перебираете исходный фрейм данных по его строкам, когда используете df.T.iteritems ()

oulenz
16 октября 2019 в 08:53
89

В отличие от того, что говорит cs95, есть вполне веские причины хотеть перебирать фрейм данных, поэтому новые пользователи не должны расстраиваться. Один из примеров - если вы хотите выполнить некоторый код, используя значения каждой строки в качестве входных. Кроме того, если ваш фрейм данных достаточно мал (например, менее 1000 элементов), производительность на самом деле не проблема.

oulenz
16 ноября 2019 в 12:19
3

@ cs95 Мне кажется, что фреймы данных - это формат таблицы в Python. Поэтому всякий раз, когда вы хотите читать в CSV, или у вас есть список dicts, значениями которых вы хотите манипулировать, или вы хотите выполнить простые операции соединения, группировки или окна, вы используете фрейм данных, даже если ваши данные сравнительно малы.

oulenz
16 ноября 2019 в 18:55
4

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

F.S.
18 ноября 2019 в 21:29
31

Я второй @oulenz. Насколько я могу судить, pandas - лучший выбор для чтения файла csv, даже если набор данных небольшой. Просто программировать манипулировать данными с помощью API.

cs95
25 февраля 2021 в 01:10
0

Если вы новичок в этой теме и не знакомы с библиотекой pandas, стоит сделать шаг назад и оценить, действительно ли итерация решением вашей проблемы. В некоторых случаях это так. В большинстве случаев это не так. Мой пост ниже знакомит новичков с библиотекой, облегчая им понимание концепции векторизации, чтобы они знали разницу между написанием «хорошего кода» и «просто работающим кодом», а также знали, когда какой использовать. Некоторые люди довольны последним, они могут продолжать голосовать за комментарий @oulenz сколько угодно.

user1854182
26 апреля 2021 в 05:41
0

Мне нужно сгенерировать список штатов США из двух букв + население. Что может быть лучше, чем повторение. мой df и с помощью print?

Pavindu
26 мая 2021 в 14:50
0

используйте df.apply. Для получения дополнительной информации см. geeksforgeeks.org/…

Ответы (32)

avatar
waitingkuo
10 мая 2013 в 07:07
4036

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

import pandas as pd

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

for index, row in df.iterrows():
    print(row['c1'], row['c2'])
10 100
11 110
12 120
viddik13
7 декабря 2016 в 16:24
305

Примечание: «Поскольку iterrows возвращает серию для каждой строки, он не сохраняет типы типов во всех строках». Кроме того, «Вы никогда не должны изменять то, что вы повторяете». Согласно pandas 0.19.1 docs

Aziz Alto
5 сентября 2017 в 16:30
7

@ viddik13, это отличное примечание, спасибо. Из-за этого я столкнулся с ситуацией, когда числовые значения, такие как 431341610650, читались как 4.31E+11. Есть ли способ сохранить типы dtypes?

Axel
7 сентября 2017 в 11:45
45

@AzizAlto используйте itertuples, как описано ниже. См. Также pandas.pydata.org/pandas-docs/stable/generated/…

Prateek Agrawal
5 октября 2017 в 18:22
0

Как изменится объект строки, если мы не будем использовать индексную переменную во время итерации ?? В этом случае мы должны использовать row [0], row [1] вместо меток?

James L.
1 декабря 2017 в 16:14
148

Не используйте iterrows. Itertuples работает быстрее и сохраняет тип данных. Больше информации

beep_check
3 мая 2018 в 16:55
2

если вам не нужно сохранять тип данных, iterrows в порядке. Совет @ waitkuo по разделению индекса значительно упрощает синтаксический анализ.

cs95
28 мая 2019 в 05:00
17

Из документации: «Итерация по объектам pandas обычно медленная. Во многих случаях итерация вручную по строкам не требуется [...]». Ваш ответ правильный (в контексте вопроса), но нигде об этом не упоминается, так что это не очень хороший ответ.

pgp1
8 августа 2021 в 13:34
4

Это наиболее часто копируемый ответ на coderhelper согласно coderhelper.blog/2021/04/19/…

LiteApplication
30 сентября 2021 в 14:31
0

@ pgp1 Это действительно так, и мы можем понять, почему. Очень лаконично и эффектно :)

avatar
gru
23 февраля 2022 в 09:10
3

Отказ от ответственности: Хотя здесь так много ответов, которые рекомендуют не использовать итеративный (циклический) подход (и я в основном согласен), я все же считаю его разумным подходом для следующая ситуация:

Расширить фрейм данных данными из сетевого запроса

Допустим, у вас есть большой фрейм данных, который содержит неполные пользовательские данные. Теперь вам нужно расширить эти данные дополнительными столбцами, например, пользовательскими age и gender.

.

Оба значения должны быть получены из серверного API. Затраты (время ожидания) для сетевого запроса намного превосходят итерацию кадра данных. Мы говорим о времени обращения сети в сотни миллисекунд по сравнению с ничтожно малым выигрышем при использовании альтернативных подходов к итерациям.

1 дорогостоящий сетевой запрос для каждой строки

В данном случае я бы предпочел использовать итеративный подход. Хотя сетевой запрос стоит дорого, он гарантированно запускается только один раз для каждой строки в кадре данных. Вот пример использования DataFrame.iterrows:

Пример

for index, row in users_df.iterrows():
  user_id = row['user_id']
  # trigger expensive network request once for each row
  response_dict = backend_api.get(f'/api/user-data/{user_id}')
  # extend dataframe with multiple data from response
  users_df.at[index, 'age'] = response_dict.get('age')
  users_df.at[index, 'gender'] = response_dict.get('gender')
avatar
Sachin
24 ноября 2021 в 12:39
17

У нас есть несколько вариантов сделать то же самое, многие люди поделились своими ответами.

Ниже я нашел два простых и эффективных метода:

  1. DataFrame.iterrows()
  2. DataFrame.itertuples()

Пример:

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

 #With iterrows method 

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

 #With itertuples method

 for row in df.itertuples(index=True, name='Pandas'):
     print(row.c1, row.c2)

Примечание: предполагается, что itertuples() работает быстрее, чем iterrows()

Joe Coder
2 декабря 2021 в 07:11
3

Это на самом деле отвечает на вопрос. +1

avatar
Golden Lion
7 сентября 2021 в 14:10
-1

Лучше всего преобразовать фрейм данных в словарь с помощью zip-архива, создав пару значений ключа, а затем получить доступ к значениям строки по ключу. Мой ответ показывает, как использовать словарь как альтернативу пандам. Некоторые думают, что словари и кортежи более эффективны. Вы можете легко заменить словарь списком именованных кортежей.

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

 for row in inp:
     for (k,v) in zip(row.keys(), row.values()):
         print(k,v)

вывод:

 c1 10
 c2 100
 c1 11
 c2 110
 c1 12
 c2 120
avatar
Ernesto Elsäßer
28 июля 2021 в 14:47
-1

Пожалуй, самое элегантное решение (но, конечно, не самое эффективное):

for row in df.values:
    c2 = row[1]
    print(row)
    # ...

for c1, c2 in df.values:
    # ...

Обратите внимание, что:

  • в документации явно рекомендуется использовать .to_numpy() вместо
  • созданный массив NumPy будет иметь тип dtype, который подходит для всех столбцов, в худшем случае object
  • есть веские причины не использовать цикл в первую очередь

Тем не менее, я думаю, что этот вариант должен быть включен здесь как прямое решение (как кажется) тривиальной проблемы.

avatar
Ashvani Jaiswal
3 июля 2021 в 06:58
2

df.iterrows () возвращает кортеж (a, b), где a - индекс, а b - строка.

avatar
Nephanth
26 мая 2021 в 09:09
0

Просто добавляю два цента,

Согласно принятому ответу, самый быстрый способ применить функцию к строкам - это использовать векторизованную функцию , так называемые numpy ufuncs (универсальные функции)

Но что делать, если функция, которую вы хотите применить, еще не реализована в numpy?

Хорошо, используя декоратор vectorize из numba, вы можете легко создавать ufuncs прямо в Python, например:

from numba import vectorize, float64

@vectorize([float64(float64)])
def f(x):
    #x is your line, do something with it, and return a float

Документация для этой функции находится здесь: https://numba.pydata.org/numba-doc/latest/user/vectorize.html

avatar
dna-data
4 марта 2021 в 18:50
-1

Используйте df.iloc[]. Например, используя dataframe 'rows_df':

Enter image description here

Или

Чтобы получить значения из определенной строки, вы можете преобразовать фрейм данных в ndarray.

Затем выберите значения строки и столбца следующим образом:

Enter image description here

Scratte
7 марта 2021 в 09:31
5

Рассмотрите возможность размещения кода не в изображениях, а в виде текста в блоке кода.

avatar
JohnE
21 декабря 2020 в 16:48
4

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

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

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

import pandas as pd
import numpy as np

df = pd.DataFrame( { 'x':[1,2,3,4,5,6], 'y':[1,1,1,0,1,1]  } )

#   x  y  desired_result
#0  1  1               1
#1  2  1               3
#2  3  1               6
#3  4  0               4
#4  5  1               9
#5  6  1              15

Это хороший пример, в котором вы, безусловно, могли бы написать одну строчку Pandas для достижения этой цели, хотя она не особенно удобочитаема, особенно если вы еще не достаточно опытны с Pandas:

df.groupby( (df.y==0).cumsum() )['x'].cumsum()

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

А что, если мы запишем это в виде цикла? Вы можете сделать с NumPy что-то вроде следующего:

import numba as nb

@nb.jit(nopython=True)  # Optional
def custom_sum(x,y):
    x_sum = x.copy()
    for i in range(1,len(df)):
        if y[i] > 0: x_sum[i] = x_sum[i-1] + x[i]
    return x_sum

df['desired_result'] = custom_sum( df.x.to_numpy(), df.y.to_numpy() )

Следует признать, что для преобразования столбцов DataFrame в массивы NumPy требуются небольшие накладные расходы, но основная часть кода - это всего лишь одна строка кода, которую вы могли бы прочитать, даже если вы ничего не знали о Pandas или NumPy:

if y[i] > 0: x_sum[i] = x_sum[i-1] + x[i]

И этот код на самом деле быстрее , чем векторизованный код. В некоторых быстрых тестах со 100 000 строк вышеупомянутое примерно в 10 раз быстрее, чем подход groupby . Обратите внимание, что одним из ключей к скорости является numba, который не является обязательным. Без строки «@ nb.jit» код цикла фактически примерно в 10 раз медленнее, чем подход groupby .

Очевидно, что этот пример достаточно прост, и вы, вероятно, предпочтете одну строку панд написанию цикла со связанными с ним накладными расходами. Однако есть более сложные версии этой проблемы, для которых удобочитаемость или скорость подхода цикла NumPy / numba, вероятно, имеет смысл.

avatar
François B.
2 ноября 2020 в 21:35
5

Самый простой способ - использовать функцию apply

def print_row(row):
   print row['c1'], row['c2']

df.apply(lambda row: print_row(row), axis=1)
avatar
imanzabet
2 октября 2020 в 20:30
1

Наряду с отличными ответами в этом посте я собираюсь предложить подход Разделяй и властвуй , я пишу этот ответ не для отмены других замечательных ответов, а для их выполнения другим подходом, который работал эффективно для меня. Он имеет два шага: splitting и merging фреймворка pandas:

ПРОФИ для «разделяй и властвуй»:

  • Вам не нужно использовать векторизацию или какие-либо другие методы для преобразования типа вашего фрейма данных в другой тип
  • Вам не нужно цитонизировать код, что обычно требует от вас дополнительного времени
  • И iterrows(), и itertuples() в моем случае имели одинаковую производительность по всему кадру данных
  • В зависимости от вашего выбора нарезки index вы сможете экспоненциально ускорить итерацию. Чем выше значение index, тем быстрее выполняется итерация.

Минусы «разделяй и властвуй»:

  • У вас не должно быть зависимости в процессе итерации от одного и того же кадра данных и другого среза . Это означает, что если вы хотите читать или писать из другого среза , это может быть сложно сделать.

=================== Подход «разделяй и властвуй» =================

Шаг 1: Разделение / Нарезка

На этом этапе мы собираемся разделить итерацию на весь фрейм данных. Подумайте, что вы собираетесь прочитать файл csv в pandas df, а затем перебрать его. На всякий случай у меня есть 5 000 000 записей, и я собираюсь разделить их на 100 000 записей.

ПРИМЕЧАНИЕ: Мне нужно повторить, как в другом анализе времени выполнения, описанном в других решениях на этой странице, «количество записей» имеет экспоненциальную долю «времени выполнения» при поиске в df. Основываясь на тесте на моих данных, вот результаты:

Number of records | Iteration per second
========================================
100,000           | 500 it/s
500,000           | 200 it/s
1,000,000         | 50 it/s
5,000,000         | 20 it/s

Шаг 2. Объединение

Это будет простой шаг, просто объедините все записанные файлы csv в один фрейм данных и запишите его в более крупный файл csv.

Вот пример кода:

# Step 1 (Splitting/Slicing)
import pandas as pd
df_all = pd.read_csv('C:/KtV.csv')
df_index = 100000
df_len = len(df)
for i in range(df_len // df_index + 1):
    lower_bound = i * df_index 
    higher_bound = min(lower_bound + df_index, df_len)
    # splitting/slicing df (make sure to copy() otherwise it will be a view
    df = df_all[lower_bound:higher_bound].copy()
    '''
    write your iteration over the sliced df here
    using iterrows() or intertuples() or ...
    '''
    # writing into csv files
    df.to_csv('C:/KtV_prep_'+str(i)+'.csv')



# Step 2 (Merging)
filename='C:/KtV_prep_'
df = (pd.read_csv(f) for f in [filename+str(i)+'.csv' for i in range(ktv_len // ktv_index + 1)])
df_prep_all = pd.concat(df)
df_prep_all.to_csv('C:/KtV_prep_all.csv')

Ссылка:

Эффективный способ итерации над datafreame

Объединить файлы CSV в один фрейм данных Pandas

avatar
artoby
1 июня 2020 в 16:22
12

Кратко

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

Контрольный показатель

Benchmark of iteration over rows in a Pandas DataFrame

avatar
bug_spray
24 марта 2020 в 17:57
12

Обновление : cs95 обновил свой ответ, включив в него векторизацию с простым набором символов. Вы можете просто сослаться на его ответ.


cs95 показывает, что векторизация Pandas намного превосходит другие методы Pandas для вычислений с фреймами данных.

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

Если вы добавите следующие функции в тестовый код 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]

Enter image description here

wwnde
29 августа 2021 в 00:20
0

как ты это задумал?

bug_spray
1 сентября 2021 в 02:40
1

сравнительный код cs95, для справки

avatar
Romain Capron
19 декабря 2019 в 16:02
56

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

Если вам действительно нужно перебрать фрейм данных 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) Наконец, именованный 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

avatar
morganics
10 декабря 2019 в 09:36
2

Некоторые библиотеки (например, библиотека взаимодействия 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, как указано выше, но в некоторых случаях это необходимо.

avatar
Zeitgeist
17 октября 2019 в 15:26
10

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

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

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

Jason Harrison
3 декабря 2019 в 05:23
0

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

avatar
cs95
7 апреля 2019 в 10:03
1503

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

Ответ: НЕ * !

Итерация в 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 (оба получили много голосов в ответах на этот вопрос) должны использоваться в очень редких случаях, таких как создание объектов-строк / наборов имен для последовательной обработки, что на самом деле единственное, что эти функции полезны для.

Апелляция в орган

На странице документации по итерации есть огромное красное окно с предупреждением:

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

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


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

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

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


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

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

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

# 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.

Предостережения

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

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

* Ваш пробег может отличаться по причинам, указанным в разделе Предостережения выше.


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

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

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

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


Мое личное мнение *

Большинство анализов, выполненных для различных альтернатив семейству iter, проводилось через призму производительности. Однако в большинстве ситуаций вы, как правило, будете работать с набором данных разумного размера (не более нескольких тысяч или 100 тысяч строк), и производительность будет уступать простоте / удобочитаемости решения.

Вот мои личные предпочтения при выборе метода для решения проблемы.

Для новичка:

Векторизация (если возможно) ; apply(); Составьте список понятий; itertuples() / iteritems(); iterrows(); Cython

Для более опытных:

Векторизация (если возможно) ; apply(); Составьте список понятий; Cython; itertuples() / iteritems(); iterrows()

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

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

Cython занимает более низкое место в списке, потому что для правильной работы требуется больше времени и усилий. Обычно вам никогда не понадобится писать код с помощью pandas, который требует такого уровня производительности, которого не может удовлетворить даже понимание списка.

* Как и любое личное мнение, возьмите с собой кучу соли!


Дополнительная литература

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


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

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

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

viddik13
30 мая 2019 в 11:56
3

Обратите внимание, что есть важные оговорки с iterrows и itertuples. См. Этот ответ и pandas docs для получения дополнительных сведений.

LinkBerest
30 мая 2019 в 14:26
96

Это единственный ответ, который фокусируется на идиоматических методах, которые следует использовать с пандами, что делает его лучшим ответом на этот вопрос. Научитесь получать правильный ответ с помощью правильного кода (вместо ответа <50> с правильным <90> неправильный код - т.е. неэффективный, не масштабируется, слишком подходит для определенных данных) является большой частью изучения панд (и данных в целом).

Imperishable Night
24 июня 2019 в 00:58
11

Я думаю, что вы несправедливо относитесь к циклу for, так как в моих тестах они лишь немного медленнее, чем понимание списка. Уловка состоит в том, чтобы перебрать zip(df['A'], df['B']) вместо df.iterrows().

sdbbs
20 ноября 2019 в 13:57
0

Хорошо, я понимаю, что вы говорите, но если мне нужно распечатать каждую строку (с числовыми данными) таблицы, отсортированную по возрастанию - я думаю, нет другого способа, кроме как перебирать строки, верно?

cs95
20 ноября 2019 в 15:37
1

@sdbbs есть, используйте sort_values ​​для сортировки ваших данных, затем вызовите to_string () для результата.

David Wasserman
16 января 2020 в 20:44
3

В разделе «Составление списков» пример «итерации по нескольким столбцам» требует предостережения: DataFrame.values преобразует каждый столбец в общий тип данных. DataFrame.to_numpy() тоже делает то же самое. К счастью, мы можем использовать zip с любым количеством столбцов.

cs95
16 января 2020 в 20:52
0

@DavidWasserman, это фантастическое замечание, спасибо за ваши комментарии. В самом деле, это то, чего следует остерегаться со смешанными столбцами, если вы сначала не конвертируете в объект (что, зачем вам)!

c z
29 января 2020 в 18:00
0

Интересно, поскольку iterrows, apply и понимание списка, похоже, имеют тенденцию к O (n) масштабируемости, я бы избегал каких-либо микрооптимизаций и выбрал наиболее удобочитаемую. Набор данных, слишком медленный при использовании любого метода, скорее всего, потребует времени, потраченного на поиск решения, отличного от Pandas , вместо того, чтобы пытаться сократить миллисекунды на for -цикле.

cs95
29 января 2020 в 19:08
1

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

bug_spray
24 марта 2020 в 05:24
1

Я знаю, что опаздываю на отвечающую сторону, но если вы конвертируете фрейм данных в массив numpy, а затем используете векторизацию, это даже быстрее, чем векторизация фреймов данных pandas (и это включает время, чтобы превратить его обратно в серию фреймов данных). Например: 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]

cs95
24 марта 2020 в 06:01
0

@AndreRicardo, почему бы не опубликовать это в ответе, где это станет более заметным?

Mike_K
11 мая 2020 в 02:05
1

На самом деле это то, что мне было трудно найти, идя по пути Google, описанному в ответе. Спасибо за это!

Aleksandr Panzin
20 мая 2020 в 23:20
1

К сожалению, у некоторых из нас нет возможности последовать вашему предложению. Потому что некоторые библиотеки просто принудительно используют DataFrame без необходимости. (Я здесь пытался перебрать паркетный файл в Python без Spark и преобразовать данные в JSON. И я вынужден использовать DataFrame) Если вы пишете библиотеки - пожалуйста, не забывайте не навязывать нам Pandas.

cs95
26 июля 2020 в 04:46
3

@Dean Я получаю такой ответ довольно часто, и, честно говоря, меня это смущает. Все дело в формировании хороших привычек. «Мои данные малы, а производительность не имеет значения, поэтому мое использование этого антипаттерна может быть оправдано» ..? Когда однажды производительность действительно будет иметь значение, вы будете благодарить себя за то, что заранее подготовили нужные инструменты.

sh37211
29 июля 2021 в 20:18
0

Примеры кода, следующие за «Формула проста, ...», посвящены итерации по столбцу или жестко заданной группе столбцов. Некоторые из нас хотят выполнять одну операцию для каждой строки со всеми данными в строке, то есть использовать все числа и текст (например, имена файлов), без необходимости жестко кодировать каждое имя столбца. Отредактируйте пример кода, чтобы было понятнее, как целые строки улучшили бы этот ответ.

cs95
1 августа 2021 в 19:02
0

@ sh37211 случай «итерации по нескольким типам» может быть расширен, чтобы удовлетворить это требование: result = [f(row[0], ..., row[n]) for row in df.to_numpy()] должен просто работать, и никакого жесткого кодирования не требуется. Разве это не то, что вам нужно?

avatar
mjr2000
16 марта 2019 в 22:33
2

В этом примере 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])
avatar
Hossein
27 февраля 2019 в 00:29
10

Для просмотра и изменения значений я бы использовал 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 для выполнения работы.

avatar
shubham ranjan
19 января 2019 в 06:53
7

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

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]])
avatar
Zach
27 июня 2018 в 18:48
14

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

# 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}
avatar
Herpes Free Engineer
23 апреля 2018 в 14:53
10

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

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, , индекс добавляется как первый элемент кортежа , что может быть нежелательно для некоторых приложений.

avatar
Lucas B
17 января 2018 в 09:41
45

Я искал Как выполнить итерацию по строкам и здесь: и закончились столбцы <2051764>

for i, row in df.iterrows():
    for j, column in row.iteritems():
        print(column)

Romain Capron
20 июля 2020 в 09:00
0

По возможности следует избегать использования iterrows (). Я объясняю почему в ответе Как эффективно выполнять итерацию

avatar
James L.
1 декабря 2017 в 17:49
3

Вы также можете выполнить индексацию 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
avatar
piRSquared
7 ноября 2017 в 04:15
22

Вы можете написать свой собственный итератор, реализующий 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);

enter image description here

enter image description here

James L.
1 декабря 2017 в 16:06
4

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

avatar
Grag2015
2 ноября 2017 в 10:33
20
 for ind in df.index:
     print df['c1'][ind], df['c2'][ind]
Bazyli Debowski
10 сентября 2018 в 12:41
1

какова производительность этого параметра при использовании в большом фрейме данных (например, миллионы строк)?

Grag2015
25 октября 2018 в 13:52
0

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

cs95
18 апреля 2019 в 23:19
4

Это цепная индексация. Не используйте это!

avatar
Pedro Lobito
11 марта 2017 в 22:44
20

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

for x in range(len(date_example.index)):
    print date_example['Date'].iloc[x]
cs95
18 апреля 2019 в 23:20
1

Это цепная индексация. Я не рекомендую этого делать.

Pedro Lobito
19 апреля 2019 в 01:42
0

@ cs95 Что бы вы порекомендовали вместо этого?

cs95
19 апреля 2019 в 01:57
0

Если вы хотите, чтобы эта работа работала, вызовите df.columns.get_loc, чтобы получить целочисленную позицию индекса столбца даты (вне цикла), а затем используйте один вызов индексации iloc внутри.

avatar
viddik13
7 декабря 2016 в 16:41
478

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

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

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

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

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

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

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

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

Используйте вместо DataFrame.apply ():

    new_df = df.apply(lambda x: x * 2)
  • итераций:

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

Подробнее см. pandas docs на итерации.

Raul Guarini
26 января 2018 в 13:16
5

Небольшой вопрос от того, кто читает эту ветку так долго после ее завершения: как df.apply () сравнивается с itertuples с точки зрения эффективности?

Brian Burns
29 июня 2018 в 07:29
6

Примечание: вы также можете указать что-то вроде for row in df[['c1','c2']].itertuples(index=True, name=None):, чтобы включить в итератор строк только определенные столбцы.

viraptor
13 августа 2018 в 06:20
13

Вместо getattr(row, "c1") вы можете использовать только row.c1.

Noctiphobia
24 августа 2018 в 10:34
1

Я примерно на 90% уверен, что если вы используете getattr(row, "c1") вместо row.c1, вы потеряете любое преимущество в производительности itertuples, и если вам действительно нужно получить доступ к свойству через строку, вы должны вместо этого использовать iterrows.

Marlo
6 декабря 2018 в 05:39
1

Когда я попробовал это, он напечатал только значения столбцов, но не заголовки. Заголовки столбцов исключены из атрибутов строк?

viddik13
30 мая 2019 в 12:32
3

Я наткнулся на этот вопрос, потому что, хотя я знал, что есть split-apply-comb, мне все еще действительно нужно было перебирать по DataFrame (как указано в вопросе). Не у всех есть возможность улучшить с помощью numba и cython (в тех же документах говорится, что «всегда стоит сначала оптимизировать Python»). Я написал этот ответ, чтобы помочь другим избежать (иногда разочаровывающих) проблем, поскольку ни один из других ответов не упоминает эти предостережения. Вводить кого-либо в заблуждение или говорить «это правильно» никогда не входило в мои намерения. Я улучшил ответ.

Confounded
16 декабря 2019 в 17:36
0

А что, если я хочу перебрать фрейм данных с размером шага больше 1, например выбрать только каждую 3-ю строку? Спасибо

viddik13
16 декабря 2019 в 22:39
1

@Confounded Быстрый поиск в Google показывает, что вы можете использовать iloc для предварительной обработки фрейма данных: df.iloc[::5, :] предоставит вам каждую 5-ю строку. Подробнее см. в этом вопросе.

David Doria
18 июня 2021 в 12:50
1

К вашему сведению, ссылка «pandas docs on iteration» не работает.

avatar
PJay
7 сентября 2016 в 12:56
112

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

for i in range(0, len(df)):
    print df.iloc[i]['c1'], df.iloc[i]['c2']
rocarvaj
5 октября 2017 в 14:50
1

Я знаю, что этого следует избегать в пользу iterrows или ittuples, но было бы интересно узнать, почему. Есть предположения?

Ken Williams
18 января 2018 в 19:22
15

Это единственный известный мне допустимый метод, если вы хотите сохранить типы данных, а также ссылаться на столбцы по имени. itertuples сохраняет типы данных, но избавляется от любых имен, которые ему не нравятся. iterrows делает наоборот.

Sean Anderson
19 сентября 2018 в 12:13
6

Потратил часы, пытаясь преодолеть особенности структур данных pandas, чтобы сделать что-то простое И выразительное. Это приводит к читаемому коду.

Kim Miller
14 декабря 2018 в 18:18
0

Хотя for i in range(df.shape[0]) может немного ускорить этот подход, он все равно примерно в 3,5 раза медленнее, чем подход iterrows (), описанный выше для моего приложения.

Bastiaan
3 января 2019 в 22:07
1

На больших Datafrmes это кажется лучше, поскольку my_iter = df.itertuples() требует вдвое больше памяти и много времени для ее копирования. то же самое для iterrows().

avatar
e9t
20 сентября 2015 в 13:52
173

Хотя 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
Alex
20 сентября 2015 в 17:00
8

Большая часть разницы во времени в ваших двух примерах кажется, что это связано с тем, что вы, кажется, используете индексирование на основе меток для команды .iterrows () и индексирование на основе целых чисел для команды .itertuples ().

harbun
19 октября 2015 в 13:03
3

Для фрейма данных на основе финансовых данных (временная метка и 4-кратное число с плавающей запятой) itertuples в 19,57 раз быстрее, чем iterrows на моем компьютере. Только for a,b,c in izip(df["a"],df["b"],df["c"]: работает почти так же быстро.

Abe Miessler
10 января 2017 в 22:05
9

Вы можете объяснить, почему это быстрее?

miradulo
13 февраля 2017 в 17:30
6

@AbeMiessler iterrows() помещает каждую строку данных в серию, а itertuples() - нет.

Brian Burns
5 ноября 2017 в 17:29
5

Обратите внимание, что порядок столбцов на самом деле не определен, поскольку df создается из словаря, поэтому row[1] может относиться к любому из столбцов. Как оказалось, время примерно одинаково для целочисленных столбцов и столбцов с плавающей запятой.

Alex
28 сентября 2018 в 21:57
0

@jeffhale, время, которое вы цитируете, точно такое же, как это возможно? Также я имел в виду что-то вроде row.iat [1], когда имел в виду целочисленное индексирование.

jeffhale
28 сентября 2018 в 23:33
0

@Alex, это действительно выглядит подозрительно. Я просто повторял его несколько раз, и это заняло в 3 раза больше времени, чем оно. С пандами 0.23.4. Удаляю другой комментарий, чтобы избежать путаницы.

jeffhale
28 сентября 2018 в 23:40
0

Затем при запуске на гораздо большем DataFrame, больше похожем на реальную ситуацию, itertuples был в 100 раз быстрее, чем iterrows. Itertuples для победы.

Ajasja
7 ноября 2018 в 20:53
0

Я также получаю увеличение> 50 раз i.stack.imgur.com/HBe9o.png (при переходе на метод доступа attr во втором запуске).

avatar
cheekybastard
1 июня 2015 в 06:24
114

Вы также можете использовать 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)
SRS
1 июля 2015 в 17:55
0

Обращается ли df ['price'] к имени столбца во фрейме данных? Я пытаюсь создать словарь с уникальными значениями из нескольких столбцов в файле csv. Я использовал вашу логику для создания словаря с уникальными ключами и значениями и получил сообщение об ошибке: TypeError: («Объекты 'Series' изменяемы, поэтому они не могут быть хешированы», u 'возникла с индексом 0')

SRS
1 июля 2015 в 17:57
0

Код: df ['Workclass'] = df.apply (лямбда-строка: dic_update (row), axis = 1) конец строки id = 0 конец строки def dic_update (row): если строка не в dic: dic [row] = id id = id + 1

SRS
1 июля 2015 в 19:06
0

Неважно, я понял. Строка вызова функции изменена на df_new = df ['Workclass']. Apply (то же самое)

zthomas.nc
29 ноября 2017 в 23:58
2

Значение по умолчанию для оси 0 - худшее

gented
4 апреля 2018 в 13:44
9

Обратите внимание, что apply не «итератирует» по строкам, а применяет функцию построчно. Приведенный выше код не будет работать, если вы действительно действительно нуждаетесь в итерациях и индексах, например, при сравнении значений в разных строках (в этом случае вы можете делать только итерацию).

cs95
29 июня 2019 в 20:54
0

@gented ... где вы здесь увидели слово "итератит"?

dhruvm
25 июля 2020 в 20:14
1

это подходящий ответ для панд

avatar
Wes McKinney
24 мая 2012 в 14:24
228

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

vgoklani
7 октября 2012 в 12:26
13

Это быстрее, чем преобразование DataFrame в массив numpy (через .values) и непосредственная работа с массивом? У меня такая же проблема, но в итоге я преобразовал ее в массив numpy, а затем использовал cython.

Phillip Cloud
15 июня 2013 в 21:06
12

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

Richard Wong
16 декабря 2015 в 11:41
8

Я провел небольшое тестирование времени, затрачиваемого на df.iterrows (), df.itertuples () и zip (df ['a'], df ['b']), и опубликовал результат в ответе другого вопрос: coderhelper.com/a/34311080/2142098