Чем отличаются iloc, ix и loc?

637

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

Например, скажем, мы хотим получить первые пять строк DataFrame. Как получается, что все три из них работают?

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

Может ли кто-нибудь представить три случая, когда различие в использовании яснее?

AZhao
источник
7
очень важно упомянуть сценарии SettingWithCopyWarning: stackoverflow.com/questions/20625582/… и stackoverflow.com/questions/23688307/…
Пол
9
Обратите внимание, что ix теперь запланирован как устаревший: github.com/pandas-dev/pandas/issues/14218
JohnE

Ответы:

970

Примечание: в панд версии 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

Notice 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

В более ранних версиях pandas (до 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
Отличное объяснение! У меня всегда был один связанный вопрос: какое отношение имеют loc, 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 года, `'2016-01-02 11' выберет даты и времени 2 января 2016 года со временем 11: ??: ?? .)
Алекс Райли
Если вы хотите обновить этот ответ в какой-то момент, здесь есть предложения о том, как использовать loc / iloc вместо ix github.com/pandas-dev/pandas/issues/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'
JoeCondron
источник
Является ли df.iloc [:,:] эквивалентным для всех строк и столбцов?
Алвис
Это так, как было бы df.loc[:, :]. Он может быть использован для переназначения значений всего DataFrameили создания его представления.
JoeCondron
Привет, вы знаете, почему loc и iloc принимают параметры между квадратными скобками [], а не как обычный метод между классическими скобками ()?
Морской Галантин
119

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

Смотрите мою чрезвычайно подробную серию блогов по выбору подмножества для более


.ix устарела и неоднозначна и никогда не должна использоваться

Потому .ixчто устарела, мы сосредоточимся только на различиях между .locи .iloc.

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

Обозначение среза определяется значениями start, stop и step. При разрезании по метке pandas включает в себя значение остановки в возвращаемом значении Следующие кусочки от Аарона до Дина включительно. Размер шага явно не определен, но по умолчанию равен 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является их способность выбирать строки и столбцы одновременно. В приведенных выше примерах все столбцы возвращались из каждого выбора. Мы можем выбрать столбцы с теми же типами входов, что и для строк. Нам просто нужно разделить выбор строки и столбца запятой .

Например, мы можем выбрать строки Джейн и Дина только с высотой, счетом и состоянием столбцов следующим образом:

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метода index.

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
Вау, это было одно из очень четко сформулированных и ясных объяснений, которые я когда-либо встречал в теме программирования. То, что вы объяснили в прошлом о нормальном индексировании, которое работает либо со строками, либо со столбцами, является одной из причин, по которым у нас есть loc и iloc метод. Я наткнулся на это предостережение в курсе datacamp. а.) Что возвращают df.columns и df.index? Это список строк? Если это список, разрешается ли доступ к двум элементам, подобным этому df.columns [[2,4]] в списке? б.) Могу ли я вызвать get_loc () для df.columns? в.) Зачем нам нужно называть df ['age']> 30. значения в случае iloc.
Pragun
Лучший ответчик, которого я когда-либо видел.
Макс
Это действительно хороший ответ, мне понравилось, что он мало влияет на ix, который устарел и не имеет смысла погружаться глубже. Спасибо.
Омабена