sort_values() в Pandas — сортировка данных
sorted(['слон', 'як', 'кот'], key=len)?Содержание:
- Коротко
- Сортировка по одному столбцу
- Сортировка по нескольким столбцам
- Обработка пропусков na_position
- reset_index и ignore_index
- inplace — менять оригинал или нет
- sort_values vs sort_index
- Сортировка Series
- Кастомная сортировка через key
- nlargest и nsmallest — быстрый топ
- Практические задачи
- sort_values и SQL ORDER BY
- Частые ошибки
- Связанные темы
- FAQ
Коротко
Сортировка — это первое, что вы делаете с таблицей, когда хотите хоть что-то в ней увидеть: кто принёс больше всего выручки, какие заказы самые свежие, у кого просел рейтинг. Без сортировки DataFrame — это просто куча строк в случайном порядке загрузки, и глазами в ней ничего не найти. Поэтому sort_values() встречается буквально в каждой второй задаче на pandas, и на собеседовании её просят показать почти всегда.
sort_values() сортирует DataFrame или Series по значениям одного или нескольких столбцов. Метод умеет сортировать в обе стороны, по нескольким ключам с разными направлениями, аккуратно складывать пропуски в начало или в конец и принимать кастомную функцию-ключ. Разберём все параметры по порядку — с кодом, который можно скопировать и запустить.
Сортировка по одному столбцу
import pandas as pd
df = pd.DataFrame({
'user': ['Иван', 'Анна', 'Мария', 'Пётр'],
'revenue': [5000, 12000, 3200, 8500],
'orders': [3, 7, 2, 5]
})
# По убыванию выручки
df.sort_values(by='revenue', ascending=False)
# user revenue orders
# 1 Анна 12000 7
# 3 Пётр 8500 5
# 0 Иван 5000 3
# 2 Мария 3200 2Первый аргумент — by, имя столбца. Его можно писать позиционно (df.sort_values('revenue')) или явно через by=. По умолчанию ascending=True — от меньшего к большему. Для «топа по выручке» нужен ascending=False. Обратите внимание: исходные индексы строк сохраняются и едут вместе со строками, поэтому после сортировки они идут не по порядку (1, 3, 0, 2) — это нормально и про сброс индекса будет отдельный раздел.
Сортировка по нескольким столбцам
df = pd.DataFrame({
'department': ['Sales', 'Sales', 'Dev', 'Dev', 'Sales'],
'name': ['Иван', 'Анна', 'Пётр', 'Мария', 'Олег'],
'salary': [90000, 120000, 150000, 130000, 90000]
})
# Сначала по отделу (возрастание), внутри отдела — по зарплате (убывание)
df.sort_values(by=['department', 'salary'], ascending=[True, False])
# department name salary
# 2 Dev Пётр 150000
# 3 Dev Мария 130000
# 1 Sales Анна 120000
# 0 Sales Иван 90000
# 4 Sales Олег 90000Передайте в by список столбцов и в ascending список направлений той же длины. Сортировка идёт по первому столбцу, а при равных значениях — по второму, потом по третьему и так далее. Это прямой аналог ORDER BY department ASC, salary DESC в SQL. Если передать в ascending одно значение вместо списка (ascending=False), оно применится сразу ко всем столбцам из списка — удобно, когда направление одинаковое.
Обработка пропусков na_position
df = pd.DataFrame({
'name': ['Иван', 'Анна', 'Пётр', 'Мария'],
'score': [85, None, 92, None]
})
# NaN в конце (по умолчанию)
df.sort_values('score')
# name score
# 0 Иван 85.0
# 2 Пётр 92.0
# 1 Анна NaN
# 3 Мария NaN
# NaN в начале
df.sort_values('score', na_position='first')
# name score
# 1 Анна NaN
# 3 Мария NaN
# 0 Иван 85.0
# 2 Пётр 92.0Пропуски (NaN) не участвуют в сравнении и всегда складываются в одну кучу — вопрос лишь, в начало или в конец. По умолчанию na_position='last', то есть NaN уходят вниз независимо от направления сортировки. Поставьте na_position='first', когда хотите сразу увидеть строки с дырами в данных — это удобный приём при анализе пропусков перед заполнением или удалением.
reset_index и ignore_index
# Индексы перемешаны после сортировки
sorted_df = df.sort_values('revenue', ascending=False)
print(sorted_df.index) # Index([1, 3, 0, 2])
# Способ 1: reset_index
sorted_df = df.sort_values('revenue', ascending=False).reset_index(drop=True)
print(sorted_df.index) # RangeIndex(start=0, stop=4, step=1)
# Способ 2: ignore_index прямо в sort_values
sorted_df = df.sort_values('revenue', ascending=False, ignore_index=True)
print(sorted_df.index) # RangeIndex(start=0, stop=4, step=1)После сортировки индекс перемешан. Если он вам нужен чистым (0, 1, 2, ...), есть два пути. Классический — дописать .reset_index(drop=True): без drop=True старый индекс не выбросится, а превратится в новый столбец. Короче — передать ignore_index=True прямо в sort_values(), тогда результат сразу получит свежий RangeIndex без лишнего вызова. Параметр ignore_index доступен начиная с pandas 1.0 и делает ровно то же, что reset_index(drop=True), только в одну строку.
inplace — менять оригинал или нет
df = pd.DataFrame({'revenue': [5000, 12000, 3200]})
# НЕ меняет df — возвращает новый DataFrame
df.sort_values('revenue')
# Меняет df на месте, возвращает None
df.sort_values('revenue', inplace=True)
# Рекомендуемый способ — переприсваивание
df = df.sort_values('revenue')По умолчанию sort_values() ничего не портит в оригинале — он возвращает новый отсортированный DataFrame, а исходный остаётся как был. Это главная ловушка новичков: написали df.sort_values('revenue'), посмотрели на оригинал — и он не отсортирован. Чтобы зафиксировать результат, либо переприсвойте (df = df.sort_values('revenue')), либо передайте inplace=True. Важно: при inplace=True метод возвращает None, поэтому такую запись нельзя ставить в цепочку — df.sort_values('revenue', inplace=True).head() упадёт с AttributeError. На практике лучше избегать inplace и работать через переприсваивание: код читается яснее и спокойно встраивается в цепочки методов.
sort_values vs sort_index
df = pd.DataFrame(
{'value': [30, 10, 20]},
index=['c', 'a', 'b']
)
df.sort_values('value') # по значениям столбца value: 10, 20, 30
# value
# a 10
# b 20
# c 30
df.sort_index() # по меткам индекса: a, b, c
# value
# a 10
# b 20
# c 30Два разных метода, которые часто путают. sort_values() упорядочивает строки по данным внутри столбца, а sort_index() — по меткам индекса (строковым или числовым), не глядя на содержимое. Типичный кейс для sort_index() — вернуть таблицу к исходному порядку после группировки или восстановить хронологию, когда индексом служит дата. У sort_index() есть тот же набор параметров: ascending, na_position, inplace, и можно сортировать по столбцам через axis=1.
Сортировка Series
s = pd.Series([30, 10, 20], index=['c', 'a', 'b'])
s.sort_values() # по значениям: a=10, b=20, c=30
s.sort_values(ascending=False) # по убыванию: c=30, b=20, a=10
s.sort_index() # по индексу: a=10, b=20, c=30У Series те же два метода, только без аргумента by — сортировать всё равно нечего, кроме единственной колонки значений. Это пригождается сплошь и рядом: результат value_counts() или groupby().sum() — это Series, и его почти всегда хочется отсортировать. Например, df['city'].value_counts().sort_values(ascending=False) даёт частоты от самых популярных городов к редким (хотя value_counts() и так возвращает результат отсортированным по убыванию — об этом подробнее в гайде по value_counts).
Кастомная сортировка через key
# Сортировка без учёта регистра
df.sort_values('name', key=lambda x: x.str.lower())
# Сортировка по длине строки
df.sort_values('name', key=lambda x: x.str.len())
# Сортировка по абсолютному значению
df.sort_values('change', key=lambda x: x.abs())Параметр key принимает функцию, которая преобразует столбец перед сравнением. Важная деталь: функция получает на вход всю колонку как Series (а не отдельные ячейки), поэтому внутри нужны векторные операции — x.str.lower(), x.str.len(), x.abs(). Сами данные при этом не меняются: ключ влияет только на порядок строк, в таблице остаются исходные значения. Так удобно сортировать без учёта регистра, по модулю отклонения или по любому производному признаку, не заводя отдельный столбец.
nlargest и nsmallest — быстрый топ
# Топ-3 по выручке
df.nlargest(3, 'revenue')
# Антитоп-3
df.nsmallest(3, 'revenue')
# По нескольким столбцам (для разрешения ничьих)
df.nlargest(5, ['revenue', 'orders'])Когда нужен не весь отсортированный DataFrame, а только верхушка, nlargest(n, col) и nsmallest(n, col) короче и быстрее, чем sort_values().head(n). Они не сортируют всю таблицу целиком, а используют partial sort и вытаскивают только нужные n строк — на больших данных разница в скорости заметна. По второму столбцу в списке разрешаются ничьи: при равной выручке выше встанет строка с большим числом заказов.
Практические задачи
Топ-10 пользователей по выручке
top_users = (
df.groupby('user_id')['amount']
.sum()
.sort_values(ascending=False)
.head(10)
)Сортировка событий по времени
df['event_time'] = pd.to_datetime(df['event_time'])
df = df.sort_values('event_time')Хронологическая сортировка — первый шаг для построения воронок и анализа пользовательских путей: пока события не выстроены по времени, посчитать «что было раньше» невозможно.
Ранжирование внутри групп
df['rank'] = (
df.sort_values(['department', 'salary'], ascending=[True, False])
.groupby('department')
.cumcount() + 1
)Или через rank():
df['salary_rank'] = df.groupby('department')['salary'].rank(
ascending=False, method='dense'
)Это прямой аналог ROW_NUMBER / RANK / DENSE_RANK в SQL. Такие задачи на сортировку, агрегацию и оконные функции — самая частая часть практической секции на собесе аналитика; отработать их в формате квиза можно в тренажёре Python.
sort_values и SQL ORDER BY
| Pandas | SQL |
|---|---|
df.sort_values('col') |
ORDER BY col ASC |
df.sort_values('col', ascending=False) |
ORDER BY col DESC |
df.sort_values(['a', 'b'], ascending=[True, False]) |
ORDER BY a ASC, b DESC |
df.nlargest(10, 'col') |
ORDER BY col DESC LIMIT 10 |
Если вы пришли в pandas из SQL, проще всего держать в голове это соответствие: sort_values — это ORDER BY, а nlargest — это ORDER BY ... DESC LIMIT n. Разница в деталях: в SQL порядок NULL зависит от диалекта, а в pandas им управляет na_position. Подробнее о сортировке на стороне базы — в гайде по ORDER BY.
Частые ошибки
Забывают ascending=False. По умолчанию сортировка идёт по возрастанию. Для «топ по выручке» или «самые свежие даты» нужно явно указать ascending=False, иначе наверху окажутся минимальные значения.
Думают, что sort_values меняет оригинал. Метод возвращает новый DataFrame и не трогает исходный. Чтобы изменения сохранились — переприсвойте (df = df.sort_values('col')) или передайте inplace=True. Самая частая причина бага «я отсортировал, а ничего не изменилось».
Ставят inplace=True в цепочку. При inplace=True метод возвращает None, поэтому df.sort_values('col', inplace=True).head() падает с AttributeError: 'NoneType' object has no attribute 'head'. В цепочках методов используйте обычный sort_values() без inplace.
Сортируют числа как строки. Если столбец хранит числа в виде строк ('10', '2', '9'), сравнение будет лексикографическим и порядок получится '10', '2', '9'. Перед сортировкой приведите тип: df['col'] = df['col'].astype(int).
Путают sort_values и sort_index. sort_values сортирует по данным столбца, sort_index — по меткам индекса. Если после sort_values индекс «перемешался», это не баг — добавьте ignore_index=True или reset_index(drop=True).
Связанные темы
- Как сортировать DataFrame в Pandas
- groupby в Pandas
- value_counts в Pandas
- iloc vs loc в Pandas
- Шпаргалка по Pandas
FAQ
Как отсортировать DataFrame по нескольким столбцам в разных направлениях?
Передайте список столбцов и список направлений той же длины: df.sort_values(['col1', 'col2'], ascending=[True, False]). Первый столбец сортируется по возрастанию, второй — по убыванию, при равенстве первого значения сравнивается второй.
Чем nlargest лучше, чем sort_values + head?
nlargest использует partial sort со сложностью порядка O(n + k·log n) и не сортирует всю таблицу, а sort_values делает полную сортировку O(n·log n). На больших данных, когда нужна только верхушка, nlargest заметно быстрее и читается короче.
Как поставить NaN в начало при сортировке?
Передайте na_position='first': df.sort_values('col', na_position='first'). По умолчанию значение 'last', и пропуски уходят в конец независимо от направления сортировки.
Чем sort_values отличается от sort_index?
sort_values упорядочивает строки по значениям выбранного столбца, а sort_index — по меткам индекса, не глядя на содержимое. sort_index обычно нужен, чтобы вернуть исходный порядок строк или восстановить хронологию, когда индексом служит дата.
Как сохранить отсортированный DataFrame?
Используйте переприсваивание: df = df.sort_values('col'). Это явнее, чем inplace=True, и не ломает цепочки методов. Чтобы заодно обнулить перемешанный индекс, добавьте ignore_index=True.
Стабильная ли сортировка в pandas?
По умолчанию pandas использует quicksort, который не гарантирует стабильность. Если важно сохранить относительный порядок строк с одинаковым ключом, передайте kind='mergesort' (или kind='stable') — это стабильный алгоритм. При сортировке по нескольким столбцам стабильность не нужна: порядок задают сами ключи.
Где потренировать сортировку и pandas?
Сортировка — базовая операция, но на собесе её спрашивают вместе с группировкой и оконными функциями. Отработать такие задачи в формате квиза можно в тренажёре Карьерник, а больше примеров вопросов — в разделе с примерами.