iloc vs loc в Pandas — в чём разница

Коротко

loc выбирает данные по меткам (именам строк и столбцов). iloc — по числовым позициям, как обычная индексация в Python. Главное различие: срезы в loc включают обе границы, а в iloc правая граница исключается.

loc — индексация по меткам

loc[строки, столбцы] использует метки индекса и имена столбцов. Если индекс — числа, loc всё равно работает по значениям индекса, а не по позициям.

import pandas as pd

df = pd.DataFrame({
    'name': ['Анна', 'Борис', 'Вика', 'Глеб'],
    'city': ['Москва', 'Питер', 'Казань', 'Москва'],
    'salary': [80000, 120000, 95000, 110000]
}, index=['a', 'b', 'c', 'd'])

# Одна строка по метке
df.loc['b']
# name      Борис
# city      Питер
# salary    120000

# Несколько строк + конкретные столбцы
df.loc[['a', 'c'], ['name', 'salary']]
#    name   salary
# a  Анна    80000
# c  Вика    95000

# Срез по меткам — обе границы включены
df.loc['a':'c', 'name':'city']
#     name    city
# a   Анна    Москва
# b   Борис   Питер
# c   Вика    Казань

Срез 'a':'c' вернул строки a, b и c — правая граница включена. Это отличается от стандартного поведения Python.

iloc — индексация по позициям

iloc[строки, столбцы] работает как обычная индексация в Python: по целочисленным позициям, с исключением правой границы в срезах.

# Первая строка
df.iloc[0]
# name      Анна
# city      Москва
# salary    80000

# Строки 0, 1, 2 и столбцы 0, 2
df.iloc[0:3, [0, 2]]
#    name   salary
# a  Анна    80000
# b  Борис   120000
# c  Вика    95000

# Последняя строка
df.iloc[-1]
# name      Глеб
# city      Москва
# salary    110000

Срез 0:3 вернул строки с позициями 0, 1, 2 — позиция 3 исключена, как в обычном Python.

Булева фильтрация с loc

loc принимает булеву маску — это основной способ фильтрации данных:

# Все из Москвы
df.loc[df['city'] == 'Москва']
#    name   city    salary
# a  Анна   Москва  80000
# d  Глеб   Москва  110000

# Зарплата > 100k, только имя и зарплата
df.loc[df['salary'] > 100000, ['name', 'salary']]
#     name    salary
# b   Борис   120000
# d   Глеб    110000

С iloc булева фильтрация тоже работает, но столбцы указываются числами — менее читаемо.

at и iat — быстрый доступ к одному значению

Для скалярного доступа к одной ячейке есть at (по метке) и iat (по позиции). Они быстрее loc/iloc, когда нужно ровно одно значение.

# По метке
df.at['b', 'salary']   # 120000

# По позиции
df.iat[1, 2]            # 120000

На большом DataFrame разница в скорости заметна — at/iat в 5-10 раз быстрее loc/iloc для скалярного доступа.

Типичные ошибки

Путаница при числовом индексе

Когда индекс DataFrame — целые числа, loc и iloc ведут себя по-разному:

df2 = pd.DataFrame(
    {'val': [10, 20, 30]},
    index=[5, 10, 15]
)

df2.loc[5]    # строка с индексом 5 → val: 10
df2.iloc[5]   # IndexError — в DataFrame только 3 строки
df2.iloc[0]   # первая строка → val: 10

Это самый частый источник багов. Если индекс числовой — всегда явно используйте loc или iloc, не полагайтесь на df[5].

Off-by-one в срезах

# loc: включает обе границы
df.loc['a':'c']   # 3 строки: a, b, c

# iloc: правая граница исключена
df.iloc[0:3]      # 3 строки: позиции 0, 1, 2
df.iloc[0:2]      # 2 строки: позиции 0, 1

Простое правило: iloc ведёт себя как range() в Python, loc — нет.

Практические примеры

# Топ-3 по зарплате
df_sorted = df.sort_values('salary', ascending=False)
top3 = df_sorted.iloc[:3]

# Обновить значение по условию
df.loc[df['city'] == 'Питер', 'salary'] = 130000

# Первые N строк конкретного столбца
first_five_names = df.iloc[:5, df.columns.get_loc('name')]

Если вы хотите отработать индексацию на практике — откройте тренажёр и порешайте вопросы по Pandas.

Вопросы с собеседований

В чём разница между loc и iloc? — loc выбирает данные по меткам индекса и именам столбцов, iloc — по числовым позициям. В срезах loc включает обе границы, iloc исключает правую — как стандартный Python.

Что произойдёт, если индекс числовой и вы используете loc[1]? — loc ищет строку с меткой индекса 1, а не первую строку. Если метки 1 в индексе нет — KeyError. Для первой строки по позиции нужен iloc[0].

Как выбрать строки по условию и конкретные столбцы?df.loc[df['col'] > 10, ['col_a', 'col_b']]. loc принимает булеву маску для строк и список имён столбцов.

Чем at отличается от loc? — at возвращает скалярное значение одной ячейки и работает быстрее. loc может возвращать Series, DataFrame или скаляр — он более универсальный, но медленнее для точечного доступа.

Можно ли использовать отрицательные индексы в iloc? — Да. iloc[-1] — последняя строка, iloc[-3:] — последние три строки. В loc отрицательные индексы работают только если они есть в метках индекса.

FAQ

Можно ли обойтись без loc и iloc?

df['col'] вернёт столбец, df[df['col'] > 10] отфильтрует строки. Но для одновременного выбора строк и столбцов, для присвоения значений по условию и для однозначного кода loc/iloc обязательны.

Почему loc включает правую границу, а iloc — нет?

loc работает с метками, которые могут быть строками, датами, чем угодно — «следующий элемент после метки» не всегда определён. Поэтому обе границы включаются. iloc работает как стандартный Python (range, списки), где правая граница исключается.

Когда использовать at/iat вместо loc/iloc?

Когда точно нужно одно значение — например, в цикле или при точечном обновлении ячейки. В обычном анализе данных loc/iloc удобнее и читабельнее.

Что дальше

Разобрались с индексацией — переходите к группировке: groupby в Pandas. Если нужна шпаргалка по всем основным методам — шпаргалка по Pandas. Больше примеров вопросов — в каталоге, а отработать всё на практике можно в Python-тренажёре.