Перейти к содержимому

Фильтрация и сортировка

Фильтрация позволяет выбрать строки, которые соответствуют указанному условию.

Сортировка упорядочивает строки по заданному критерию.

Как и другие операции DataFrame, Filter и SortBy не изменяют исходную таблицу. Они возвращают новый DataFrame.

var good := df.Filter(row -> row['Балл'] >= 80);

Если результат нужен дальше, его нужно сохранить в переменную или продолжить цепочку операций.

Filter принимает условие для одной строки таблицы. Если условие истинно, строка попадает в результат.

uses MLABC;
begin
var df := DataFrame.FromCsvText('''
Имя,Класс,Возраст,Балл
Анна,8А,14,91
Борис,8Б,15,76
Вера,8А,14,84
Глеб,8Б,15,68
Дина,8А,14,95
''');
var good := df.Filter(row -> row['Балл'] >= 80);
good.Print;
end.

Вывод:

Имя Класс Возраст Балл
Анна 8А 14 91
Вера 8А 14 84
Дина 8А 14 95

В условии row -> row['Балл'] >= 80 переменная row обозначает текущую строку таблицы.

Условия можно объединять с помощью and, or и скобок. Например, выберем продажи продуктов, где количество не меньше 2.

uses MLABC;
begin
var df := DataFrame.FromCsvText('''
Товар,Категория,Количество,Цена
Хлеб,Продукты,2,45.50
Молоко,Продукты,1,72.90
Блокнот,Канцтовары,3,120
Яблоки,Продукты,4,58.25
Ручка,Канцтовары,5,35
''');
var res := df.Filter(row ->
(row['Категория'] = 'Продукты') and
(row['Количество'] >= 2)
);
res.Print;
end.

Вывод:

Товар Категория Количество Цена
Хлеб Продукты 2 45.50
Яблоки Продукты 4 58.25

Если в столбце есть пропуски, перед сравнением удобно проверить, что значение существует. Для значения ячейки доступно свойство IsValid.

uses MLABC;
begin
var df := DataFrame.FromCsvText('''
Имя,Класс,Возраст,Балл
Анна,8А,14,91
Борис,8Б,15,76
Вера,8А,14,84
Глеб,8Б,15,68
Дина,8А,14,95
Егор,8Б,15,NA
''');
var res := df.Filter(row ->
row['Балл'].IsValid and
(row['Балл'] >= 80)
);
res.Print;
end.

Вывод:

Имя Класс Возраст Балл
Анна 8А 14 91
Вера 8А 14 84
Дина 8А 14 95

row['Балл'].IsValid означает: в этой строке в столбце Балл есть настоящее значение, а не NA.

Заметим, что в данном случае если поле Балл содержит значение NA, то любые операции сравнения возвращают False поэтому в данном примере достаточно писать

var res := df.Filter(row -> row['Балл'] >= 80);

не проверяя специально ячейку row['Балл'] на IsValid.

SortBy сортирует таблицу по указанному столбцу.

uses MLABC;
begin
var df := DataFrame.FromCsvText('''
Имя,Класс,Возраст,Балл
Анна,8А,14,91
Борис,8Б,15,76
Вера,8А,14,84
Глеб,8Б,15,68
Дина,8А,14,95
''');
var sorted := df.SortBy('Балл');
sorted.Print;
end.

Вывод:

Имя Класс Возраст Балл
Глеб 8Б 15 68
Борис 8Б 15 76
Вера 8А 14 84
Анна 8А 14 91
Дина 8А 14 95

По умолчанию сортировка идёт по возрастанию.

Для сортировки по убыванию используется параметр descending.

uses MLABC;
begin
var df := DataFrame.FromCsvText('''
Имя,Класс,Возраст,Балл
Анна,8А,14,91
Борис,8Б,15,76
Вера,8А,14,84
Глеб,8Б,15,68
Дина,8А,14,95
''');
var sorted := df.SortBy('Балл', descending := True);
sorted.Print;
end.

Такой вариант удобен, когда нужно увидеть сначала самые большие значения: лучшие баллы, самые высокие цены, крупнейшие города.

Можно сортировать таблицу сразу по нескольким столбцам. Например, сначала по классу, а внутри каждого класса по баллу.

uses MLABC;
begin
var df := DataFrame.FromCsvText('''
Имя,Класс,Возраст,Балл
Анна,8А,14,91
Борис,8Б,15,76
Вера,8А,14,84
Глеб,8Б,15,68
Дина,8А,14,95
''');
var sorted := df.SortBy(['Класс', 'Балл'], [False, True]);
sorted.Print;
end.

Во втором массиве задаётся направление сортировки для каждого столбца:

  • False — по возрастанию;
  • True — по убыванию.

В примере классы идут по возрастанию, а баллы внутри класса — от большего к меньшему.

Фильтрацию, сортировку и выбор столбцов можно объединять в цепочку преобразований. Это возможно потому, что каждое преобразование возвращает новый DataFrame, к которому сразу применяется следующее преобразование. Так код обработки таблицы остаётся коротким и читаемым.

uses MLABC;
begin
var df := DataFrame.FromCsvText('''
Имя,Класс,Возраст,Балл
Анна,8А,14,91
Борис,8Б,15,76
Вера,8А,14,84
Глеб,8Б,15,68
Дина,8А,14,95
Егор,8Б,15,NA
''');
var res := df
.Filter(row -> row['Балл'] >= 80)
.SortBy('Балл', descending := True)
.Select(['Имя', 'Класс', 'Балл']);
res.Print;
end.

Вывод:

Имя Класс Балл
Дина 8А 95
Анна 8А 91
Вера 8А 84

Такой стиль читается как последовательность шагов: оставить хорошие результаты с баллом не менее 80, отсортировать, выбрать нужные столбцы.

  • Filter оставляет строки, для которых условие истинно.
  • SortBy возвращает новую отсортированную таблицу.
  • Исходный df при этом не меняется.
  • Для пропусков можно использовать row['ИмяСтолбца'].IsValid.
  • Несколько операций удобно объединять в цепочку.