Як перебрати рядки в DataFrame в Pandas?


1943

У мене є 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 ()
Стефан Груенвальд

11
Якщо ви не новачок у цій темі і є початківцем для панди, НЕ ІТЕРІУЙТЕ !! Ітерація через фрейми даних є анти-закономірністю, і те, чого ви не повинні робити, якщо не хочете звикнути до багато очікування. Залежно від того, що ви намагаєтеся зробити, можливі набагато кращі альтернативи . iter*функції слід використовувати в дуже рідкісних обставинах. Також пов'язані .
cs95

18
На відміну від того, що говорить cs95, є цілком точні причини, щоб хотіти повторювати рамки даних, тому нові користувачі не повинні почувати себе зневіреними. Один із прикладів - якщо ви хочете виконати якийсь код, використовуючи значення кожного рядка як вхідні дані. Крім того, якщо ваш кадр даних досить малий (наприклад, менше 1000 елементів), продуктивність насправді не є проблемою.
Оуленц

1
@oulenz: Якщо з якоїсь дивної причини ви хочете летіти перед використанням API для тієї мети, для якої він був розроблений (високоефективні перетворення даних), будьте моїм гостем. Але принаймні, не використовуйтеiterrows , є кращі способи ітерації через DataFrame, ви також можете просто повторити список списків у цей момент. Якщо ви знаходитесь в точці, коли ви нічого не робите, окрім ітерації через DataFrames, взагалі немає користі від використання DataFrame (припустимо, що повторення над ним - єдине, що ви робите з цим). Просто мій 2с.
cs95

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

Відповіді:


2628

DataFrame.iterrow - це генератор, який дає і індекс, і рядок

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

206
Примітка: "Оскільки iterrow повертає серію для кожного рядка, вона не зберігає типи в рядках." Крім того, "Ви ніколи не повинні змінювати те, що ви повторюєте". Згідно з пандами 0,19,1 документа
viddik13

3
@ viddik13 це чудова подяка. Через це я натрапив на випадок, коли числові значення на зразок 431341610650де читаються як 4.31E+11. Чи є спосіб зберегти типи?
Азіз Альто

26
@AzizAlto використовувати itertuples, як пояснено нижче. Дивіться також pandas.pydata.org/pandas-docs/stable/generated/…
Axel

100
Не використовуйте iterrow. Itertuples швидше і зберігає тип даних. Більше інформації
Джеймс Л.

11
З документації : "Ітерація через об'єкти панди, як правило, повільна. У багатьох випадках ітерація вручну через рядки не потрібна [...]". Ваша відповідь правильна (в контексті запитання), але ніде її не згадуйте, тому вона не дуже хороша.
cs95

453

Як перебрати рядки в DataFrame в Pandas?

Відповідь: НЕ * !

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

Ви хочете надрукувати DataFrame? ВикористовуйтеDataFrame.to_string() .

Ви хочете щось обчислити? У такому випадку знайдіть методи в цьому порядку (список, змінений тут ):

  1. Векторизація
  2. Програми цитонів
  3. Означення списку (ванільна forпетля)
  4. DataFrame.apply(): i) Скорочення, які можна виконати в цитоні, ii) Ітерація в просторі пітона
  5. DataFrame.itertuples() і iteritems()
  6. DataFrame.iterrows()

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

Звернення до авторитету
На сторінці документів на ітерації є величезне червоне поле попередження, яке говорить:

Ітерація через об’єкти панди, як правило, повільна. У багатьох випадках ітерація вручну над рядками не потрібна [...].

* Це насправді трохи складніше, ніж "не робити". df.iterrows()є правильною відповіддю на це запитання, але "векторизуйте свої операційні" - це краще. Я визнаю, що існують обставини, коли ітерації неможливо уникнути (наприклад, деякі операції, де результат залежить від значення, обчисленого для попереднього рядка). Однак, щоб дізнатися, коли, знадобиться деяке знайомство з бібліотекою. Якщо ви не впевнені, чи потрібно вам ітеративне рішення, ви, мабуть, цього не зробите. PS: Щоб дізнатися більше про моє обґрунтування написання цієї відповіді, перейдіть до самого низу.


Швидше, ніж циклічно: векторизація , цитон

Значна кількість основних операцій та обчислень "векторизується" пандами (або через NumPy, або через цитонізовані функції). Сюди входять арифметичні, порівняння, (більшість) скорочень, перестановки (такі як поворотні), з'єднання та групові операції. Перегляньте документацію про основні функціональні можливості щоб знайти відповідний векторний метод для вашої проблеми.

Якщо такої немає, сміливо пишіть власні, використовуючи спеціальні розширення 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'])]

Якщо ви можете вкласти свою логіку бізнесу у функцію, ви можете використати розуміння списку, яке викликає її. Ви можете змусити довільно складні речі працювати простотою і швидкістю необробленого пітона.

Зрозуміння
списку Caveats передбачає, що з вашими даними легко працювати - це означає, що ваші типи даних є послідовними та у вас немає NaN, але це не завжди може бути гарантовано.

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

* YMMV з причин, викладених у розділі " Caveats " вище.


Очевидний приклад

Продемонструємо різницю простим прикладом додавання двох стовпців панди A + B. Це опектон, що ветеризується, тому легко буде протиставити ефективність методів, обговорених вище.

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

Код тестування для довідки.

Але я мушу зазначити, що це не завжди така порізка і суха. Іноді відповідь на те, "який найкращий метод для операції" - це "це залежить від ваших даних". Моя порада - перевірити різні підходи до своїх даних, перш ніж зупинитися на одному.


Подальше читання

* Строкові методи Pandas "векторизовані" в тому сенсі, що вони вказані на серії, але працюють на кожен елемент. Основні механізми все ще є ітераційними, оскільки струнні операції за своєю суттю важко векторизувати.


Чому я написав цю відповідь

Поширена тенденція, яку я помічаю від нових користувачів, - задавати питання форми "як я можу повторити свій df, щоб зробити X?". Показ коду, який дзвонить iterrows(), роблячи щось усередині циклу. Ось чому. Новий користувач бібліотеки, який не ознайомився з поняттям векторизації, швидше за все, передбачає код, який вирішує їх проблему як ітерацію над своїми даними, щоб щось зробити. Не знаючи, як перебирати DataFrame, перше, що вони роблять, це Google це, і, нарешті, тут, на це питання. Потім вони бачать прийняту відповідь, яка говорить їм, як це робити, і вони закривають очі і виконують цей код, не замислюючись про те, чи ітерація не потрібна.

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


22
Це єдина відповідь, яка зосереджена на ідіоматичних прийомах, які слід використовувати при пандах, що робить її найкращою відповіддю на це питання. Навчання отримувати правильну відповідь за допомогою правильного коду (замість правильної відповіді з неправильним кодом - тобто неефективним, не масштабує, занадто підходить до конкретних даних) - велика частина навчальних панд (і даних загалом).
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з будь-якою кількістю стовпців.
Девід Вассерман

396

Спочатку подумайте, чи дійсно вам потрібно повторити рядки в DataFrame. Дивіться цю відповідь щодо альтернатив.

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

itertuples() має бути швидше, ніж iterrows()

Але майте на увазі, згідно з документами (на сьогодні панд 0.24.2):

  • iterrow: dtypeможе не збігатися з рядка в рядок

    Оскільки iterrow повертає серію для кожного рядка, вона не зберігає типи в рядках (dtypes зберігаються в стовпцях для DataFrames). Щоб зберегти типи під час ітерації над рядками, краще використовувати itertuples (), який повертає найменування значень значень і, як правило, набагато швидше, ніж iterrows ()

  • iterrow: Не змінюйте рядки

    Ніколи не слід змінювати щось, над чим ви повторюєте. Це не гарантовано працює у всіх випадках. Залежно від типів даних ітератор повертає копію, а не перегляд, і запис на неї не матиме ефекту.

    Використовуйте натомість DataFrame.apply () :

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

    Імена стовпців будуть перейменовані на позиційні імена, якщо вони є недійсними ідентифікаторами Python, повторюються або починаються з підкреслення. З великою кількістю стовпців (> 255) повертаються регулярні кортежі.

Докладніші відомості див. У документах Pandas про ітерацію .


4
Лише невелике запитання від того, хто читає цю тему так довго після її завершення: як df.apply () по ефективності порівнюється з itertuples?
Рауль Гуаріні

4
Примітка. Ви також можете сказати щось на зразок for row in df[['c1','c2']].itertuples(index=True, name=None):включення до ітератора рядків лише певних стовпців.
Брайан Бернс

12
Замість цього getattr(row, "c1")можна використовувати просто row.c1.
viraptor

1
Я приблизно на 90% впевнений, що якщо ви використовуєте getattr(row, "c1")замість цього row.c1, ви втрачаєте будь-яку перевагу в продуктивності itertuples, і якщо вам дійсно потрібно дістатися до ресурсу за допомогою рядка, вам слід скористатися iterrow.
Noctiphobia

3
Я натрапив на це питання, тому що, хоча я знав, що існує розділене застосування-поєднання, мені все-таки потрібно було повторити перелік даних DataFrame (як зазначено в питанні). Не у всіх є розкіш, щоб покращити її ( numbaі cythonті ж документи говорять, що "Завжди варто оптимізувати в Python в першу чергу"). Я написав цю відповідь, щоб допомогти іншим уникати (іноді засмучуючих) питань, оскільки жодна з інших відповідей не згадує про ці застереження. Вводити в оману когось або казати "це правильно робити" ніколи не був моїм наміром. Я вдосконалив відповідь.
viddik13

201

Ви повинні використовувати df.iterrows(). Хоча ітерація рядок за рядком не є особливо ефективною, оскільки Seriesоб’єкти потрібно створювати.


12
Це швидше, ніж перетворення DataFrame в масив numpy (через .values) і безпосередньо робота з масивом? У мене така ж проблема, але в результаті перетворився на нумерований масив, а потім використовував cython.
вгоклані

12
@vgoklani Якщо ітерація рядок за рядком неефективна і у вас є масив без об’єктів numpy, то майже напевно використання необробленого масиву numpy буде швидше, особливо для масивів з багатьма рядками. вам слід уникати повторень над рядками, якщо вам абсолютно не доведеться
Phillip Cloud

7
Я трохи перевірив витрату часу на df.iterrow (), 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

5
Значна різниця у ваших двох прикладах здається, що це пов’язано з тим, що, здається, ви використовуєте індексацію на основі міток для команди .iterrow () та індексації на основі цілого числа для команди .itertuples ().
Олексій

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

7
Чи можете ви пояснити, чому це швидше?
Абе Місслер

4
@AbeMiessler вказує iterrows()кожен рядок даних у Серію, тоді як itertuples()ні.
miradulo

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: ("Об'єкти" серії "є змінними, тому їх не можна хешировать", u'ccurred в індексі 0 ')
SRS

Код: df ['Workclass'] = df.apply (рядок лямбда: dic_update (рядок), вісь = 1) кінець рядка id = 0 кінець рядка def dic_update (рядок): якщо рядок не в dic: dic [рядок] = id id = id + 1
SRS

Неважливо, я це зрозумів. Змінено лінію виклику функції на df_new = df ['Workclass']. Застосувати (те саме)
SRS


9
Зауважте, що applyне "ітератизується" над рядками, скоріше він застосовує функцію в рядку. Наведений вище код не буде не працювати , якщо ви дійсно робите ітерації потрібна , і індекси, наприклад , при порівнянні значень в різних рядках (в цьому випадку ви можете зробити нічого , крім ітерацію).
покладено

82

Ви можете використовувати функцію df.iloc наступним чином:

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

1
Я знаю, що слід уникати цього на користь iterrow або 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);

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

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


2
Для людей, які не хочуть читати код: синя лінія є intertuples, помаранчева лінія - це список ітераторів через блок урожайності. interrowsне порівнюється
Джеймс Л.

18

Як ітератувати ефективно?

Якщо вам дійсно доведеться повторити кадр даних панди, ви, ймовірно, захочете уникати використання iterrow () . Існують різні методи, і звичайний iterrows()далеко не найкращий. itertuples () може бути в 100 разів швидшим.

Коротко:

  • Як загальне правило, використовуйте df.itertuples(name=None). Зокрема, коли у вас стовпці з фіксованою кількістю та менше 255 стовпців. Див. Пункт (3)
  • В іншому випадку використовуйте, df.itertuples()за винятком випадків, якщо у ваших стовпцях є спеціальні символи, такі як пробіли або '-'. Див. Пункт (2)
  • Можна використовувати itertuples()навіть якщо у вашому кадрі даних є дивні стовпці, використовуючи останній приклад. Див. Пункт (4)
  • Використовуйте лише iterrows()якщо ви не можете попередніх рішень. Див. Пункт (1)

Різні методи перебору рядків у фреймі даних панди:

Створіть випадковий кадр даних з мільйоном рядків і 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()використовуючи ім'я = 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

Ця стаття є дуже цікавим порівнянням між ітерами та ітералями


14

Для циклу всіх рядків у a dataframeви можете використовувати:

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

1
Це ланцюгова індексація. Я не рекомендую цього робити.
cs95

@ cs95 Що б ти рекомендував замість цього?
CONvid19

Якщо ви хочете зробити цю роботу, зателефонуйте df.column.get_loc, щоб отримати ціле число індексу стовпця дати (поза циклом), а потім використовуйте один виклик індексації iloc всередині.
cs95

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

1
як працює цей параметр при використанні у великому кадрі даних (наприклад, мільйони рядків)?
Базили Дебовський

Чесно кажучи, я точно не знаю, я вважаю, що порівняно з найкращою відповіддю минулий час буде приблизно однаковим, оскільки обидва випадки використовують "для" -конструкції. Але пам'ять може бути різною.
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}

6

Для того, щоб петлі всі рядки в 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, індекс додається в якості першого елемента кортежу , який може бути небажаним для деяких застосувань.


5

Існує спосіб ітерації кинутих рядків, отримуючи DataFrame взамін, а не Series. Я не бачу, щоб хтось згадував, що ви можете передавати індекс у вигляді списку для повернення рядка у вигляді DataFrame:

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

Зверніть увагу на використання подвійних дужок. Це повертає DataFrame з одним рядком.


Це було дуже корисно для отримання n-го найбільшого рядка в кадрі даних після сортування. Дякую!
Джейсон Харрісон

3

Як для перегляду, так і для зміни значень, я б використовував iterrows(). У циклі a 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 вище, що, на мою думку, має бути прийнятою відповіддю. У своїй відповіді він показує, що векторизація панд набагато перевершує інші методи панд для обчислення даних з фреймами даних.

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

Якщо до базового коду @ 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])

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.