Фильтрование данных


Главная » Ресурсы » Здесь

Фильтрование данных — важнейший компонент аналитики цепей поставок. Envision обеспечивает широкую поддержку данного процесса. Фильтрование вводится с помощью условий where и when, которые можно использовать для отсеивания либо больших блоков сценария, либо отдельных операторов. В данном разделе вы найдете указания по практическому использованию этих средств.


Образец сценария

Давайте начнем с образца набора данных, который можно найти в папке /sample в вашей учетной записи Lokad. Сценарий, приведенный ниже, достаточно сложен, и он содержит некоторые образцы фильтров, доступные в Envision. Если вы еще не прочитали статью «Ведение расчетов с помощью Envision», мы рекомендуем сделать это, прежде чем обратиться к данному разделу.
read "/sample/Lokad_Items.tsv"
read "/sample/Lokad_Orders.tsv" as O

show label "Filtering data" a1f1 tomato

oend := max(O.Date)

when date > oend - 365
  LastYearQty = sum(O.Quantity)
  where StockOnHand + StockOnOrder > LastYearQty
    show table "Overstocked items, +1 year of stock" a2f3 tomato with 
      Id
      Name
      StockOnHand + StockOnOrder as "Stock"
      LastYearQty

  where O.NetAmount > 1000
    show table "Large transactions over $1000" a4f5 tomato with 
      Id
      Name 
      O.Date 
      O.Quantity
      O.NetAmount
      O.Client

lastDay := monday(oend)
firstDay := lastDay - 52 * 7
when date >= firstDay & date < lastDay
  Week.sold := sum(O.NetAmount)
  show linechart "Sold by week" a6f7 tomato unit:"$" with
    Week.sold
Для начала рекомендуем скопировать этот сценарий в вашу учетную запись Lokad и выполнить его, чтобы получить соответствующую панель управления. Если все сделано правильно, вы должны увидеть следующую панель управления.

Image

Блоки фильтров

Если пользователь начинает работать со всеми историческими данными, полученными не ранее одного года назад, то скорее всего, это потребует выполнения множества расчетов. В такой ситуации ко всем расчетам необходимо применить фильтр только за последний год (last year only). Поэтому в Envision фильтрование данных в основном происходит в блоках кода. Фрагмент сценария ниже имеет два вложенных блока фильтров. Первый блок начинается в 1-й строке с оператора when, а второй второй блок — в 3-й строке с оператора where.
when date > oend - 365
  LastYearQty = sum(O.Quantity)
  where StockOnHand + StockOnOrder > LastYearQty
    show table "Overstocked items, +1 year of stock" a2f3 tomato with
      Id
      Name
      StockOnHand + StockOnOrder as "Stock"
      LastYearQty
В языке Envision пробелы в начале строки играют большое значение. Несколько последовательных строк, начинающихся с одного и того же количества пробелов, называются блоком кода, и блоки могут вкладываться друг в друга (один блок может включать в себя другой блок).

Если вы впервые сталкиваетесь с такой структурой в программировании, она может показаться вам немного непонятной. Однако на практике редактор кода Envision неплохо помогает пользователю: когда вы нажимаете клавишу Enter в конце строки, содержащей фильтр, следующая строка автоматически начинается с двух пробелов.

Для разработчиков. Использование пробелов в Envision напоминает Python. Данный подход отлично совместим с Envision, где упор также делается на использование краткого синтаксиса для обработки данных. В Envision нет циклов и ветвлений, поэтому количество отступов редко превышает 3 уровня, что упрощает работу с пробелами на практике.

Блок фильтра начинается с условия (см. подробнее ниже), которое может быть истинным или ложным для любой строки любой таблицы. В пределах блока фильтра остаются только те строки, для которых условие является истинным, тогда как все остальные строки отфильтровываются. Оператор when отвечает за фильтрацию по времени, он применим ко всем таблицам со столбцом Date. Оператор where обычно используется для фильтрации наименований, и при его использовании фильтр применяется ко всем таблицам со столбцом Id.

При вводе блока в сценарий Envision происходит отбор строк таблицы, удовлетворяющих условию. В противном случае, все остается как было, и любая часть сценария, которую можно записать вне блока, может быть перемещена в блок. В частности, в блоке можно задать еще один блок фильтра. Данная процедура называется вложением. В примере выше блок where, который начинается в третьей строке, вложен в блок when, который начинается в первой строке.

Создание условия

Условие — это выражение, которое может быть истинным или ложным. Понятие фильтрования основано на создании условий, которые оцениваются с помощью входящих данных и, возможно, с помощью результатов, полученных в ходе промежуточных вычислений. Envision позволяет создавать разнообразные условия, как показано в следующем сценарии:
lastDay := monday(oend)
firstDay := lastDay - 52 * 7
when date >= firstDay & date < lastDay
  Week.sold := sum(O.NetAmount)
  show linechart "Sold by week" a6f7 tomato unit:"$" with
    Week.sold
В данном сегменте оператор and говорит о том, что оба выражения, слева и справа от оператора, должны быть истинными. Логические операторы, поддерживаемые Envision, включают в себя следующее: and, or и not. Кроме того, числа можно сравнивать с помощью числовых операторов: == (равенство), != (неравенство), <= (меньше или равно), >= (больше или равно), < (меньше), > (больше). В следующем сегменте кода показано, как эти операторы сочетаются и оцениваются.
a := 1 > 10 // false
b := not a // true
c := a | b // true
d := a & b // false
e := 10 >= 3 | 5 > 7 // true
show table "Conditions" with a, b, c, d, e
Если один блок фильтра вложен в другой блок фильтра, это равносильно использованию оператора and с двумя условиями, помещенными слева и справа от оператора and.

В примере выше можно заметить сегмент monday(oend). Это вызов функции с именем monday. Данная функция возвращает дату последнего понедельника, который наступает не позже даты, указанной в качестве аргумента (включая ее). Таким образом, если в качестве аргумента указан понедельник, функция вернет ту же самую дату.

Данная функция monday() используется для определения временного периода, состоящего из целых недель (вместо неполных недель). При выполнении еженедельного объединения данных должны использоваться только целые недели, в противном случае значения за первый и последний временной период могут быть необъективно низкими только по той причине, что учитываются неполные недели.

Фильтрование таблиц по дате

Envision позволяет фильтровать данные таблиц с помощью разнообразных временных условий. В сценарии, который мы только что рассмотрели, применен фильтр строк, которым более 1 года. Давайте подробно рассмотрим соответствующий сегмент сценария.
oend := max(O.Date)
when date > oend - 365
  LastYearQty = sum(O.Quantity)
Envision обрабатывает даты как количество дней в виде целых чисел, начиная с 1 января 2001 года. Это дает системе определенные преимущества, включая выполнение арифметических действий с датами. Например, вычитание 7 дней из определенной даты дает вам соответствующую дату на предыдущей неделе, а вычитание 365 дней — дату (приблизительную) в прошлом году.

Ключевое слово date работает особым образом. Переменная date ссылается на все таблицы, в которых есть столбец Date. В данном случае используется только одна таблица, O, так что мы могли бы написать O.Date > oend - 365. Однако синтаксис date не только более краткий, он также применяется ко всем актуальным таблицам сразу. Если вместо объема продаж нам нужно было бы использовать объем закупок, мы могли бы прописать сценарий следующим образом:
// загрузка файла PurchaseOrders
read "/sample/Lokad_PurchaseOrders.tsv" as PO

// опущено

when date > oend - 365
  LastYearQty = sum(PO.Quantity)

Фильтр наименований

Помимо фильтрования строк по дате Envision также позволяет фильтровать наименования, что также часто требуется, когда пользователь хочет исключить какие-либо продукты, организации, категории и т. д. Сценарий, приведенный в начале данного раздела, показывает, как можно ограничить список наименований теми, которые попадают в категорию неликвидных. Соответствующие строки показаны ниже.
  where StockOnHand + StockOnOrder > LastYearQty
    show table "Overstocked items, +1 year of stock" a2f3 tomato with
      Id
      Name
      StockOnHand + StockOnOrder as "Stock"
      LastYearQty
Условие вводится после ключевого слова where. Условие применяется к трем векторам, которые принадлежат таблице Items. Это единственная таблица, имя которой не нужно указывать в виде префикса перед именем переменной. Например, при работе с таблицей заказов O нужно прописывать выражение O.NetAmount, а не только NetAmount. Условие можно прочитать следующим образом: включать только наименования, для которых сумма наличных запасов и заказанных запасов больше, чем количество наименований, проданных за прошлый год.

Когда условие для таблицы Items задано, все таблицы, имеющие столбец Id — то есть идентификаторы наименований в строках в соответствии с требованиями Envision — фильтруются таким же образом. Данная функция работает точно так же, как фильтрование по времени, описанное выше. При применении фильтра наименований не имеет смысла сохранять строки, содержащие данные о продажах или закупках, которые больше не привязаны к наименованиям, так как эти наименования были отфильтрованы.

Фильтр наименований влияет на определение области заново рассчитанных векторов. Проиллюстрируем эту мысль небольшим примером.
where StockOnHand > 5
  GreaterThanFive = "yes"
  show table "Hello" with
    Name
    GreaterThanFive // ВЕРНО!

// начиная с этой строки мы вышли из блока фильтра
show table "Hello" with
  Name
  GreaterThanFive // НЕВЕРНО!
В пятой строке присутствует ошибка, потому что вектор GreaterThanFive был определен только в строках, где условие StockOnHand > 10 истинно. Таким образом, этот вектор правильно задан в пределах блока, и потому он может быть использован, как показано в 5-й строке, однако данный вектор нельзя использовать вне блока фильтра, потому что некоторые его значения останутся неопределенными. Данную ситуацию можно исправить, надлежащим образом определив вектор для всех значений наименований, как показано ниже.
GreaterThanFive = "no"

where StockOnHand > 5
  GreaterThanFive = "yes"
  show table "Hello" with
    Name
    GreaterThanFive // ВЕРНО!

// начиная с этой строки мы вышли из блока фильтра
show table "Hello" with
  Name
  GreaterThanFive // ВЕРНО!
Этот сегмент начинается с определения вектора GreaterThanFive для всех наименований (первая строка). Данное определение повторяется в четвертой строке для подгруппы наименований. Однако этот повтор не влияет на то, что вектор GreaterThanFive открыто задан для всех наименований, и в результате задача отображения в двенадцатой строке теперь не имеет ошибок.

Фильтрование произвольных таблиц

Фильтрование дат и наименований очень полезно, однако иногда требуется точное фильтрование конкретной таблицы. Эта задача также может быть выполнена с помощью ключевого слова where. Рассмотрим строки, которые иллюстрируют эту возможность Envision.
  where O.NetAmount > 1000
    show table "Large transactions over $1000" a4f5 tomato with
      Id
      Name
      O.Date
      O.Quantity
      O.NetAmount
      O.Client
Здесь мы фильтруем таблицу O, исключая все строки таблицы со значениями менее 1000 долларов. Строки, которые не отфильтровываются, отображаются с помощью оператора show table во второй и третьей строках. Данный пример показывает, как одна таблица может быть отфильтрована. Данный фильтр влияет только на таблицу O, и данное условие не применяется к остальным таблицам.

Если вектор, привязанный к таблице O, рассчитывается в пределах блока фильтра, то доступ к этому вектору ограничен непосредственно самим блоком. Мы уже наблюдали подобное поведение при работе с наименованиями. Рассмотрим теперь, как система работает с произвольными таблицами в таких ситуациях.
where O.NetAmount > 1000
  O.LargeTxn = "yes"
  show table "Large transactions" with
    Name
    O.LargeTxn // ВЕРНО!
  // последняя строка блока
// отсуп отсутствует, так как блок закончился
show table "Large transactions" with
  Name
  O.LargeTxn // НЕВЕРНО!
Вектор O.LargeTxn не задан для всех строк таблицы O, поэтому верной является только пятая строка, а десятая строка неверна. Также как и в предыдущем примере, сценарий можно исправить, определив надлежащим образом значение LargeTxn для всей таблицы O. Это можно сделать с помощью сценария, приведенного ниже.
O.LargeTxn = "no"
where O.NetAmount > 1000
  O.LargeTxn = "yes"
  show table "Large transactions" with
    Name
    O.LargeTxn // ВЕРНО!
  // последняя строка блока
// отсуп отсутствует, так как блок закончился
show table "Large transactions" with
  Name
  O.LargeTxn // ВЕРНО!
Как правило, Envision стремится блокировать «утечки»: вектор, рассчитанный в пределах блока, можно использовать вне его при условии, что это не нарушает правило открытого определения всех значений вектора, если вектор указан справа от оператора присваивания.

Синтаксические приемы для фильтрования

Синтаксис Envision для фильтрования (называется filter-and-indent) — короткий и простой, однако при использовании различных фильтров сценарий со множеством отступов сложно расшифровать. Именно поэтому в Envision появились специальные синтаксические приемы, альтернативные варианты синтаксиса, для которых не требуется много отступов. Они рассматриваются в данном разделе.

Пропуск отступов при использовании нескольких фильтров

Для раздельного использования фильтров в Envision необходимо добавить 1 дополнительный отступ. Если важен лишь последний (внутренний) фильтр, то можно использовать лишь один отступ (см. пример):
// у каждого фильтра «where» 
// свой уровень отступа
where O.Quantity > 10
  where StockOnHand < 100
    show table "Filtered orders" with
      O.Quantity

// однако при использовании нескольких фильтров
// требуется лишь один отступ
where O.Quantity > 10
where StockOnHand < 100 // здесь отступа нет!
  show table "Filtered orders" with O.Quantity
Второй блок имеет ту же семантику, что и первый, но для него требуется лишь один отступ. В общем виде синтаксис выглядит так:
where A
  when B
    where C
      show table "Filtered by A, B and C" with X
// то же самое
where A
when B
where C
  show table "Filtered by A, B and C" with X

Объединение фильтров с помощью ключевого слова and

Мы уже видели, что в Envision логический оператор И представлен символом &. Тем не менее в Envision также есть ключевое слово and, которое имеет немного другую семантику:
// два вложенных фильтра «where»
where O.NetAmount > 1000 
  where StockOnHand > 10
    show table "Filtered transactions" with
      Name
      O.Quantity

// можно переписать как единый фильтр с помощью ключевого слова «and»
where O.NetAmount > 1000 and StockOnHand > 10
  show table "Filtered transactions" with 
    Name
    O.Quantity
Использование ключевого слова and является строго эквивалентным использования фильтров where. С помощью ключевого слова and можно последовательно вводить различные фильтры, используя при этом лишь один отступ. В общем виде мы имеем следующее:
where A
  where B
   where C
     // опущено

// можно переписать
where A and B and C
  // опущено
На практике ключевое слово and позволяет совмещать различные фильтры, которые не нужно использовать по-отдельности.

Нулевой отступ (ключевое слово keep)

Очень часто при составлении сценариев фильтры прописываются в самом начале, чтобы ограничить масштаб анализа данных Синтаксис фильтров в Envision достаточно хорошо работает в данных ситуациях, однако в результате весь сценарий Envision будет иметь отступы на один-два уровня. Ключевое слово keep позволяет убрать отступы:
// с фильтра «where» начинается блок с отступом
where O.Quantity > 10
  // начало блока
  show table "Inside the filter" with
    sum(O.Quantity)
  // конец блока
show table "Outside the filter" with
  sum(O.Quantity)

// однако при использовании оператора «keep»
// фильтр применяется без отступа
keep where O.Quantity > 10
show table "Inside the filter" with
  sum(O.Quantity)
Ключевое слово keep нужно ставить перед where или when, так как оно показывает, что фильтр применяется без отступов. Фильтр остается активным до конца заданного диапазона данных.
where A
  keep where B
  show table "Filtered by A and B" with X
  // конец фильтров А и В
show table "Not filtered" with X
Таким образом, если keep прописать в строке сценария без отступа, то фильтр применяется до самого конца сценария.

Суффигированные строчные фильтры

Пока что мы рассматривали фильтры, заданные в виде блоков фильтров. Однако Envision также позволяет использовать иные, более компактные конструкции, которые называются условными суффиксами. Вернемся к расчету объема продаж за прошлый год.
when date > oend - 365
  LastYearQty = sum(O.Quantity)
Этот сценарий можно прописать следующим образом:
LastYearQty = sum(O.Quantity) when date > oend - 365
Пользователям, знакомым с реляционными базами данных, такая конструкция может напомнить задание условий с оператором where в SQL. В Envision такой синтаксис позволяет избежать создания блоков, состоящих из 1 строки, когда в блоке нужно прописать всего одно выражение. Операторы where и when можно прописывать в виде «суффиксов» справа от операции присваивания.

Агрегаторы можно фильтровать с помощью операторов when и where. Envision также позволяет добавить к условию модификатор else. Например, нельзя написать:
oend := max(O.Date)
lastDay := monday(oend)
Week.sold := sum(O.NetAmount) when date < lastDay
show linechart "Sold by week" with
  Week.sold // НЕВЕРНО
Потому что параметр Week.sold задан не для всего диапазона, что происходит из-за фильтра в предыдущей строке. Однако если добавить else, мы сможем правильно задать Week.sold:
oend := max(O.Date)
lastDay := monday(oend)
Week.sold := sum(O.NetAmount) when date < lastDay else 0
show linechart "Sold by week" with
  Week.sold // ВЕРНО