Чим iloc, ix та loc відрізняються?


635

Чи може хтось пояснити, чим відрізняються ці три методи нарізки?
Я бачив документи і бачив ці відповіді , але все ще не можу пояснити, чим три різні. Мені вони здаються значною мірою взаємозамінними, оскільки вони знаходяться на нижчих рівнях нарізки.

Наприклад, скажімо, що ми хочемо отримати перші п'ять рядків DataFrame. Як так працюють усі троє?

df.loc[:5]
df.ix[:5]
df.iloc[:5]

Чи може хтось подати три випадки, коли відмінність у використанні чіткіша?


7
Дуже важливо згадати сценарії SettingWithCopyWarning: stackoverflow.com/questions/20625582/… та stackoverflow.com/questions/23688307/…
Павло

9
Зауважте, що зараз ix планується знизити
JohnE

Відповіді:


968

Примітка: в панд версії 0.20.0 і вище, ixє застарілим і використання locі ilocрекомендується замість цього. Частини цієї відповіді я залишив ixнедоторканим як посилання на користувачів попередніх версій панд. Нижче додано приклади, що показують альтернативи ix .


По-перше, ось резюме трьох методів:

  • locотримує рядки (або стовпці) з певними мітками з індексу.
  • ilocотримує рядки (або стовпці) на певних позиціях в індексі (тому він займає лише цілі числа).
  • ixзазвичай намагається вести себе так, locале відпадає від поведінки, ilocніби мітка відсутня в індексі.

Важливо відзначити деякі тонкощі, які можуть зробити ixтрохи складними у використанні:

  • якщо індекс має цілочисельний тип, ixвін використовуватиме лише індексацію на основі міток і не повернеться до індексації на основі позиції. Якщо мітка відсутня в індексі, виникає помилка.

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


Для ілюстрації відмінностей між трьома методами розглянемо наступні серії:

>>> s = pd.Series(np.nan, index=[49,48,47,46,45, 1, 2, 3, 4, 5])
>>> s
49   NaN
48   NaN
47   NaN
46   NaN
45   NaN
1    NaN
2    NaN
3    NaN
4    NaN
5    NaN

Ми розглянемо нарізки з цілим значенням 3.

У цьому випадку s.iloc[:3]повертає нам перші 3 ряди (оскільки вона трактує 3 як позицію) і s.loc[:3]повертає нам перші 8 рядків (оскільки вона трактує 3 як мітку):

>>> s.iloc[:3] # slice the first three rows
49   NaN
48   NaN
47   NaN

>>> s.loc[:3] # slice up to and including label 3
49   NaN
48   NaN
47   NaN
46   NaN
45   NaN
1    NaN
2    NaN
3    NaN

>>> s.ix[:3] # the integer is in the index so s.ix[:3] works like loc
49   NaN
48   NaN
47   NaN
46   NaN
45   NaN
1    NaN
2    NaN
3    NaN

Повідомлення s.ix[:3]повертає ту саму Серію, s.loc[:3]оскільки вона спочатку шукає мітку, а не працює над позицією (а індекс для sцілого типу).

Що робити, якщо ми спробуємо з цілою міткою, яка не входить до індексу (скажімо 6)?

Тут s.iloc[:6]повертаються перші 6 рядків серії, як очікувалося. Однак s.loc[:6]підвищує KeyError, оскільки 6його немає в індексі.

>>> s.iloc[:6]
49   NaN
48   NaN
47   NaN
46   NaN
45   NaN
1    NaN

>>> s.loc[:6]
KeyError: 6

>>> s.ix[:6]
KeyError: 6

Відповідно до тонкощів, зазначених вище, s.ix[:6]тепер виникає KeyError, оскільки він намагається працювати як, locале не може знайти 6в індексі. Оскільки наш індекс цілого типу ixне повертається до такої поведінки iloc.

Якщо, проте, наш індекс був змішаного типу, задане ціле число поводилось ixби як ilocодразу замість підвищення KeyError:

>>> s2 = pd.Series(np.nan, index=['a','b','c','d','e', 1, 2, 3, 4, 5])
>>> s2.index.is_mixed() # index is mix of different types
True
>>> s2.ix[:6] # now behaves like iloc given integer
a   NaN
b   NaN
c   NaN
d   NaN
e   NaN
1   NaN

Майте на увазі, що ixвсе ще можна приймати нецілі числа та вести себе так loc:

>>> s2.ix[:'c'] # behaves like loc given non-integer
a   NaN
b   NaN
c   NaN

Як загальна порада, якщо ви лише індексуєте за допомогою міток або лише індексуєте за допомогою цілих позицій, дотримуйтесь locабо ilocуникайте несподіваних результатів - намагайтеся не використовувати ix.


Поєднання індексації на основі позиції та етикетки

Іноді даючи DataFrame, вам потрібно буде змішати методи мітки та позиції для індексації рядків та стовпців.

Наприклад, розглянемо таку DataFrame. Як найкраще нарізати рядки до «c» і включити перші чотири стовпці?

>>> df = pd.DataFrame(np.nan, 
                      index=list('abcde'),
                      columns=['x','y','z', 8, 9])
>>> df
    x   y   z   8   9
a NaN NaN NaN NaN NaN
b NaN NaN NaN NaN NaN
c NaN NaN NaN NaN NaN
d NaN NaN NaN NaN NaN
e NaN NaN NaN NaN NaN

У попередніх версіях панд (до 0.20.0) ixви можете робити це досить акуратно - ми можемо нарізати рядки за міткою, а стовпчики за позицією (зауважте, що для стовпців ixза замовчуванням буде розрізання на основі позиції, оскільки 4це не назва стовпця ):

>>> df.ix[:'c', :4]
    x   y   z   8
a NaN NaN NaN NaN
b NaN NaN NaN NaN
c NaN NaN NaN NaN

У більш пізніх версіях панд ми можемо досягти цього результату за ilocдопомогою іншого методу:

>>> df.iloc[:df.index.get_loc('c') + 1, :4]
    x   y   z   8
a NaN NaN NaN NaN
b NaN NaN NaN NaN
c NaN NaN NaN NaN

get_loc()- метод індексу, що означає "отримати положення мітки в цьому індексі". Зауважте, що оскільки зрізання з ilocвинятком є ​​його кінцевою точкою, ми повинні додати 1 до цього значення, якщо ми хочемо також рядок "c".

Є й інші приклади в документації панд тут .


12
Чудове пояснення! Одне з пов'язаних питань у мене завжди було, яке відношення, якщо вони є, локальні, iloc та ix мають попередження SettingWithCopy? Існує деяка документація , але, чесно кажучи , я все ще трохи збентежений pandas.pydata.org/pandas-docs/stable / ...
measureallthethings

3
@measureallthethings: loc, ilocі ixвсе ще може викликати попередження , якщо вони з'єднані один з одним. Використання прикладу DataFrame у пов'язаних документах dfmi.loc[:, 'one'].loc[:, 'second']викликає попередження так само, dfmi['one']['second']оскільки копія даних (а не перегляд) може бути повернута першою операцією індексації.
Алекс Райлі

Що ви використовуєте, якщо хочете знайти DateIndex з датою чи щось подібне df.ix[date, 'Cash']?
cjm2671

@ cjm2671: і те, locі інше ixповинно працювати в такому випадку. Наприклад, df.loc['2016-04-29', 'Cash']поверне всі індекси рядків із цією конкретною датою зі стовпця "Готівка". (Ви можете бути настільки специфічними, як вам подобається, коли ви отримуєте індекси з рядками, наприклад '2016-01', виберіть усі часові дати, що випадають на січень 2016 року. .)
Алекс Райлі

Якщо ви хочете в якийсь момент оновити цю відповідь, тут є пропозиції щодо використання loc / iloc замість ix github.com/pandas-dev/pandas/isissue/14218
JohnE

142

ilocпрацює на основі цілого позиціонування. Тому незалежно від того, якими є мітки ваших рядків, ви завжди можете, наприклад, отримати перший рядок, виконавши

df.iloc[0]

або останні п’ять рядів виконуючи

df.iloc[-5:]

Ви також можете використовувати його на стовпцях. Це отримує 3-й стовпець:

df.iloc[:, 2]    # the : in the first position indicates all rows

Ви можете комбінувати їх, щоб отримати перехрестя рядків і стовпців:

df.iloc[:3, :3] # The upper-left 3 X 3 entries (assuming df has 3+ rows and columns)

З іншого боку, .locвикористовуйте названі індекси. Давайте встановимо кадр даних із рядками як мітки рядків та стовпців:

df = pd.DataFrame(index=['a', 'b', 'c'], columns=['time', 'date', 'name'])

Тоді ми можемо отримати перший ряд

df.loc['a']     # equivalent to df.iloc[0]

а другі два ряди 'date'стовпчика по

df.loc['b':, 'date']   # equivalent to df.iloc[1:, 1]

і так далі. Тепер, це, ймовірно , варто відзначити, що в рядку за замовчуванням і індекси стовпців для DataFrameцілих чисел від 0 і в цьому випадку ilocі locбуде працювати таким же чином. Ось чому ваші три приклади рівнозначні. Якщо у вас був нечисловий індекс, такий як рядки або дати, виникне df.loc[:5] помилка.

Крім того, ви можете виконати пошук стовпців просто за допомогою кадру даних __getitem__:

df['time']    # equivalent to df.loc[:, 'time']

Тепер припустимо, що ви хочете змішати позицію та іменовану індексацію, тобто індексувати за допомогою імен у рядках та позиціях на стовпцях (для уточнення, я маю на увазі вибір із нашого кадру даних, а не створення кадру даних із рядками в індексі рядків та цілими числами у індекс стовпця). Сюди .ixвходить:

df.ix[:2, 'time']    # the first two rows of the 'time' column

Я думаю, що також варто згадати, що ви також можете передавати булеві вектори locметоду. Наприклад:

 b = [True, False, True]
 df.loc[b] 

Повернеться 1 та 3 рядки df. Це еквівалентно df[b]для вибору, але його також можна використовувати для призначення через булеві вектори:

df.loc[b, 'name'] = 'Mary', 'John'

Чи df.iloc [:,:] еквівалентний всім рядкам і стовпцям?
Елвіс

Це, як би було df.loc[:, :]. Він може бути використаний для перепризначення значень цілого DataFrameабо створення його подання.
JoeCondron

119

На мою думку, прийнята відповідь є заплутаною, оскільки вона використовує DataFrame з лише відсутніми значеннями. Я також не подобається термін позиція на основі для .ilocі замість цього, вважають за краще ціле місце , як це набагато більш змістовний і саме те , що .ilocварто. Ключове слово INTEGER - .ilocпотребує INTEGERS.

Докладніше дивіться мою надзвичайно детальну серію блогу про вибір підмножини


.ix застарілий і неоднозначний, і його ніколи не слід використовувати

Оскільки .ixзастаріле, ми зупинимося лише на відмінностях між .locта .iloc.

Перш ніж говорити про відмінності, важливо розуміти, що DataFrames мають мітки, які допомагають ідентифікувати кожен стовпець та кожен індекс. Давайте подивимось на зразок DataFrame:

df = pd.DataFrame({'age':[30, 2, 12, 4, 32, 33, 69],
                   'color':['blue', 'green', 'red', 'white', 'gray', 'black', 'red'],
                   'food':['Steak', 'Lamb', 'Mango', 'Apple', 'Cheese', 'Melon', 'Beans'],
                   'height':[165, 70, 120, 80, 180, 172, 150],
                   'score':[4.6, 8.3, 9.0, 3.3, 1.8, 9.5, 2.2],
                   'state':['NY', 'TX', 'FL', 'AL', 'AK', 'TX', 'TX']
                   },
                  index=['Jane', 'Nick', 'Aaron', 'Penelope', 'Dean', 'Christina', 'Cornelia'])

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

Усі слова жирним шрифтом - це мітки. Етикетки, age, color, food, height, scoreі stateвикористовуються для стовпців . Інші етикетки, Jane, Nick, Aaron, Penelope, Dean, Christina, Corneliaвикористовуються для індексу .


Основні способи вибору конкретних рядків у DataFrame - це за допомогою .locта .ilocіндексаторів. Кожен з цих індексаторів також може використовуватися для одночасного вибору стовпців, але наразі простіше просто зосередитись на рядках. Також кожен з індексаторів використовує набір дужок, які негайно слідують за їх назвою, щоб зробити свій вибір.

.loc вибирає дані лише мітками

Спочатку ми поговоримо про .locіндексатор, який вибирає дані лише за допомогою міток індексу чи стовпців. У нашому зразку DataFrame ми вказали значущі імена як значення для індексу. Багато DataFrames не матимуть жодних значущих імен і натомість будуть за замовчуванням лише цілі числа від 0 до n-1, де n - довжина DataFrame.

Є три різні входи, для яких можна використовувати .loc

  • Рядок
  • Список рядків
  • Позначення фрагментів, використовуючи рядки як значення старту та зупинки

Вибір одного рядка з .loc за допомогою рядка

Щоб вибрати єдиний рядок даних, розмістіть позначку індексу всередині дужок наступним чином .loc.

df.loc['Penelope']

Це повертає рядок даних у вигляді серії

age           4
color     white
food      Apple
height       80
score       3.3
state        AL
Name: Penelope, dtype: object

Вибір декількох рядків з .loc зі списком рядків

df.loc[['Cornelia', 'Jane', 'Dean']]

Це повертає DataFrame із рядками у порядку, визначеному у списку:

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

Вибір декількох рядків з .loc із позначенням фрагмента

Позначення зрізів визначаються значеннями початку, зупинки та кроку. Під час нарізки за міткою панди включають значення зупинки у зворотному порядку. Наступні фрагменти від Аарона до Діна, включно. Її розмір кроку не визначено прямо, але за замовчуванням до 1.

df.loc['Aaron':'Dean']

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

Складні фрагменти можна приймати так само, як і списки Python.

.iloc вибирає дані лише за цілим розташуванням

Тепер перейдемо до .iloc. Кожен рядок і стовпець даних у DataFrame має ціле розташування, яке визначає його. Це додатково до мітки, яка візуально відображається у висновку . Ціле розташування - це просто кількість рядків / стовпців зверху / зліва, починаючи з 0.

Є три різні входи, для яких можна використовувати .iloc

  • Ціле число
  • Список цілих чисел
  • Позначення зрізів, використовуючи цілі числа як значення старту та зупинки

Вибір одного рядка з .iloc з цілим числом

df.iloc[4]

Це повертає 5-й рядок (ціле число 4) у вигляді серії

age           32
color       gray
food      Cheese
height       180
score        1.8
state         AK
Name: Dean, dtype: object

Вибір декількох рядків з .iloc зі списком цілих чисел

df.iloc[[2, -2]]

Це повертає DataFrame третього та другого до останніх рядків:

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

Вибір декількох рядків з .iloc із позначенням фрагмента

df.iloc[:5:3]

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


Одночасний вибір рядків і стовпців з .loc та .iloc

Однією чудовою здатністю обох .loc/.ilocє їх здатність одночасно обирати і рядки, і стовпці. У наведених вище прикладах усі стовпці поверталися з кожного вибору. Ми можемо вибрати стовпці з тими ж типами входів, що і для рядків. Нам просто потрібно відокремити виділення рядків і стовпців комою .

Наприклад, ми можемо вибрати рядки Jane та Dean з висотою стовпців, оцінкою та станом так:

df.loc[['Jane', 'Dean'], 'height':]

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

При цьому використовується список міток для рядків і позначення зрізів для стовпців

Ми, природно, можемо робити подібні операції, .ilocвикористовуючи лише цілі числа.

df.iloc[[1,4], 2]
Nick      Lamb
Dean    Cheese
Name: food, dtype: object

Одночасний вибір з мітками та цілим розташуванням

.ixвикористовувались для вибору одночасно з мітками та цілим розташуванням, що було корисно, але часом заплутано та неоднозначно, і, на щастя, воно застаріле. У випадку, якщо вам потрібно зробити вибір із сумішшю міток та цілих локацій, вам доведеться зробити як вибрані мітки, так і цілі місця.

Наприклад, якщо ми хочемо вибрати рядки Nickта Corneliaразом із стовпцями 2 та 4, ми могли б використати .loc, перетворивши цілі числа на мітки із наступним:

col_names = df.columns[[2, 4]]
df.loc[['Nick', 'Cornelia'], col_names] 

Або ж перетворіть мітки індексу в цілі числа get_locметодом індексу.

labels = ['Nick', 'Cornelia']
index_ints = [df.index.get_loc(label) for label in labels]
df.iloc[index_ints, [2, 4]]

Булевий вибір

Індекс-індекс .loc також може здійснювати булевий вибір. Наприклад, якщо нам цікаво знайти всі рядки, вік яких перевищує 30 років, і повернути лише стовпці foodта scoreстовпці, ми можемо зробити наступне:

df.loc[df['age'] > 30, ['food', 'score']] 

Ви можете скопіювати це за допомогою, .ilocале ви не можете пропустити булеву серію. Ви повинні перетворити булеву серію в numpy масив на зразок цього:

df.iloc[(df['age'] > 30).values, [2, 4]] 

Вибір усіх рядків

Можна використовувати .loc/.ilocдля вибору просто стовпців. Ви можете вибрати всі рядки, скориставшись двокрапкою:

df.loc[:, 'color':'score':2]

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


Оператор індексації [], теж може вибирати рядки та стовпці, але не одночасно.

Більшість людей знайомі з основною метою оператора індексації DataFrame, а саме вибору стовпців. Рядок вибирає один стовпець у вигляді серії, а список рядків вибирає кілька стовпців як DataFrame.

df['food']

Jane          Steak
Nick           Lamb
Aaron         Mango
Penelope      Apple
Dean         Cheese
Christina     Melon
Cornelia      Beans
Name: food, dtype: object

За допомогою списку вибирається кілька стовпців

df[['food', 'score']]

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

Що люди менш знайомі, це те, що коли використовується позначення зрізів, то вибір відбувається за мітками рядків або за цілим розташуванням. Це дуже заплутано, і я майже ніколи не використовую, але це працює.

df['Penelope':'Christina'] # slice rows by label

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

df[2:6:2] # slice rows by integer location

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

Ясність .loc/.ilocвибору рядків вкрай переважна. Один оператор індексації не може одночасно вибрати рядки та стовпці.

df[3:5, 'color']
TypeError: unhashable type: 'slice'

6
Нічого собі, це було одне з дуже чітко сформульованих і чітких пояснень, що я коли-небудь стикався з темою програмування. Те, що ви пояснювали в останньому про звичайну індексацію, яка працює або на рядку, або на стовпцях, є однією з причин, коли ми маємо локальний і iloc метод. Я натрапив на цей застереження під час курсу камери даних. а.) Що повертають стовпці df.olde та df.index? Це список рядків? Якщо це список, чи дозволено отримувати доступ до двох елементів, таких як цей df.column [[2,4]] у списку? b.) Чи можу я зателефонувати get_loc () у колонках df.column? в.) Чому нам потрібно викликати df ['age']> 30.values ​​у випадку iloc.
прагун

Найкращий передвір, який я коли-небудь бачив.
Макс

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