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

1754
Roman 10 Май 2013 в 11:04

17 ответов

Лучший ответ

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
2347
cs95 21 Июн 2019 в 03:26

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

for i in range(0, len(df)):
    print df.iloc[i]['c1'], df.iloc[i]['c2']
75
PJay 7 Ноя 2016 в 09:09

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

3
Hossein 27 Фев 2019 в 00:35

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

194
cs95 11 Дек 2019 в 18:42

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

17
piRSquared 7 Ноя 2017 в 04:29

Хотя 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
146
e9t 1 Июн 2016 в 09:00

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

for x in range(len(date_example.index)):
    print date_example['Date'].iloc[x]
13
Pedro Lobito 4 Апр 2017 в 20:46

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

6
Herpes Free Engineer 24 Апр 2018 в 08:48

Вы также можете выполнить индексирование 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
James L. 1 Дек 2017 в 18:22

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

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

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

5
Zeitgeist 17 Окт 2019 в 15:26

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

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]])
1
shubham ranjan 19 Янв 2019 в 06:53

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

# 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}
6
cs95 13 Апр 2019 в 23:06

Некоторые библиотеки (например, библиотека взаимодействия 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
morganics 10 Дек 2019 в 09:36

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

for i, row in df.iterrows():
    for j, column in row.iteritems():
        print(column)
30
Lucas B 17 Янв 2018 в 09:41

В этом примере 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])
0
mjr2000 16 Мар 2019 в 22:33

Вы также можете использовать 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)
85
cheekybastard 1 Июн 2015 в 06:24
 for ind in df.index:
     print df['c1'][ind], df['c2'][ind]
14
cs95 7 Май 2019 в 06:37