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

У меня есть 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 объект и как я могу с ним работать.

Ответ 1

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

Ответ 2

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

Ответ 3

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

Ответ 4

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

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

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


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

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

Если ничего не существует, не стесняйтесь писать свои собственные, используя пользовательские расширения 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
result = [f(row[0], ..., row[n]) for row in df[['col1', ...,'coln']].values]

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


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

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

enter image description here

Код для сравнения, для справки.

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


Ссылки

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

Ответ 5

Хотя 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

Ответ 6

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

docs: 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)

Ответ 7

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

for i in range(0, len(df)):
    print df.iloc[i]['c1'], df.iloc[i]['c2']

Ответ 8

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

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

Ответ 9

Используйте itertuples(). Это быстрее, чем iterrows():

for row in df.itertuples():
    print "c1 :",row.c1,"c2 :",row.c2

Ответ 10

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

Ответ 11

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

for x in range(len(date_example.index)):
    print date_example['Date'].iloc[x]

Ответ 12

 for ind in df.index:
     print df['c1'][ind], df['c2'][ind]

Ответ 13

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

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

Ответ 14

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

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

Ответ 15

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

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

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

Ответ 16

Вы также можете сделать 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

Ответ 17

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

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

Ответ 19

В этом примере 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])

Ответ 20

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

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

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

Ответ 21

Зачем все усложнять?

Просто.

import pandas as pd
import numpy as np

# Here is an example dataframe
df_existing = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=list('ABCD'))

for idx,row in df_existing.iterrows():
    print row['A'],row['B'],row['C'],row['D']