</>
Тема 4 из 7

Сортировка и вычисляемые столбцы

Отобранные данные обычно нужно упорядочить («топ-10 товаров») и дополнить вычисленными значениями («цена со скидкой», «место в рейтинге»). В этой теме — инструменты для этого.

Сортировка

import pandas as pd

df = pd.DataFrame({
    "имя": ["Вика", "Аня", "Боря", "Гоша"],
    "баллы": [85, 92, 85, 70],
    "время": [30, 45, 25, 30],
})

print(df.sort_values("баллы"))                    # по возрастанию
print(df.sort_values("баллы", ascending=False))   # по убыванию

По нескольким столбцам

Список столбцов задаёт порядок сравнения: сначала по первому, при равенстве — по второму и так далее. Для каждого столбца можно указать своё направление:

df.sort_values(["баллы", "время"], ascending=[False, True])

Здесь выше тот, у кого больше баллов, а при равных баллах — у кого меньше время.

Сортировка возвращает новую таблицу и не меняет исходную. Индекс строк переезжает вместе со строками; чтобы пронумеровать заново, используют reset_index(drop=True).

head(k) после сортировки — классический способ взять «топ-k». Есть и короче: df.nlargest(3, "баллы"), df.nsmallest(3, "время").

map — замена по словарю

map заменяет каждое значение столбца по словарю (или функции):

sizes = pd.Series(["S", "L", "M"])
print(sizes.map({"S": 1, "M": 2, "L": 3}))     # 1, 3, 2

Значения, которых нет в словаре, превращаются в NaN — их можно заменить: .fillna(0).

apply — своя функция

apply вызывает функцию для каждого значения Series:

def grade(score):
    if score >= 90:
        return "отлично"
    if score >= 75:
        return "хорошо"
    return "надо подтянуть"

df["оценка"] = df["баллы"].apply(grade)

У таблицы apply(функция, axis=1) вызывает функцию для каждой строки — внутри доступны все столбцы строки:

df["темп"] = df.apply(lambda row: row["баллы"] / row["время"], axis=1)

Но построчный apply медленный: если выражение можно записать операциями над столбцами (df["баллы"] / df["время"]), так и делай — это в десятки раз быстрее.

Округление

df["темп"] = (df["баллы"] / df["время"]).round(2)

Для вывода с ровно двумя знаками используй форматирование: f"{x:.2f}".

rank — места

rank вычисляет место каждого значения. Параметр method задаёт, что делать с одинаковыми значениями:

scores = pd.Series([92, 85, 85, 70])
print(scores.rank(ascending=False, method="min"))     # 1, 2, 2, 4
print(scores.rank(ascending=False, method="dense"))   # 1, 2, 2, 3
print(scores.rank(ascending=False, method="first"))   # 1, 2, 3, 4
  • min — одинаковым значениям наименьшее общее место, следующее место пропускается (как в спорте);
  • dense — без пропусков;
  • first — по порядку появления.

rank возвращает дробные числа (1.0), для вывода превращай в целые: .astype(int).

Итог

  • sort_values(столбцы, ascending=[...]) — сортировка по нескольким признакам с разными направлениями;
  • head(k), nlargest, nsmallest — первые k;
  • map(словарь) — замена значений, отсутствующие становятся NaN;
  • apply(функция) — своя функция для значений; axis=1 — для строк, но это медленно;
  • rank(method="min"/"dense"/"first") — места.