Ведение расчетов


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

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

Чтобы работать с этой страницей было удобнее, мы рекомендуем воспользоваться образцом набора данных. Мы еще не описывали возможности Envision с точки зрения загрузки входящих данных, но в примерах будут показаны строки, которые необходимо прописывать в начале сценария.

Таблицы и векторы

Модель данных Envision привязана к таблицам и векторам. Таблицы Envision очень похожи на таблицы, которые используются в реляционных базах данных. С точки зрения Excel, таблица — это хорошо сформированный процессор данных, где первая строка содержит заголовки столбцов, а (остальные) строки под ней содержат данные, приведенные в соответствии с заголовками. В системе Envision таблицы также имеют имена, и они обычно выбираются, исходя из названий используемых табличных файлов. Векторы привязаны к столбцам таблицы и получают соответствующие имена. В Envision обычно используется термин «вектор», а не «столбец», чтобы показать, что операции могут выполняться по всем значениям вектора сразу, то есть во всех строках исходной таблицы.

Проиллюстрируем эту мысль несколькими строками кода, который можно использовать применительно к образцу набора данных. Ниже мы рассчитываем размер налога, то есть соотношение между суммой налога и суммой за вычетом налога, которые взимаются с клиента, для всех строк заказов.
read "/sample/Lokad_Items.tsv"
read "/sample/Lokad_Orders.tsv" as O
read "/sample/Lokad_PurchaseOrders.tsv" as PO

O.TaxRate = O.TaxAmount / O.NetAmount
Здесь O — это таблица заказов, которая содержит всю историю продаж и каждая операция в которой представлена столькими строками, сколько наименований участвует в этой операции. Переменная O.TaxAmount ссылается на вектор, привязанный к столбцу TaxAmount в таблице O. Обратите внимание на синтаксис: в нем используется точка (.) между именем таблицы и именем вектора. Такие конструкции часто встречаются в Envision.

Операция, включающая в себя знак равенства =, называется присваиванием : расчет происходит справа от знака =, а результат присваивается левой стороне оператора. В примере, приведенном выше, справа используется оператор деления. Ни O.TaxAmount, ни O.NetAmount в сценарии не определяются, поэтому Envision пытается загрузить эти данные непосредственно из исходного набора данных. Таблица O в наборе данных содержит два столбца: NetAmount и TaxAmount, поэтому сценарий выполняется успешно. Далее, слева находится оператор O.TaxRate, которому присваивается рассчитанный размер налога. Присваивание — это логический эквивалент создания нового столбца в Excel, названного в соответствии с присваиваемой переменной, то есть в данном случае это TaxRate, размер налога.

В следующих сегментах мы выпустили строки read “/sample/Lokad_XYZ.tsv” для сокращения примеров. Не забудьте, что они должны всегда присутствовать в начале сценария.

Синтаксис для расчетов в Envision напоминает синтаксис формул Excel. В сценарии, показанном ниже, мы проводим серию (довольно произвольных) расчетов, которые позволяют продемонстрировать синтаксис.
O.A = 42
O.B = 5 * (1 + O.A)
O.C = (O.A + O.B) * (1 + O.A)
В сценарии задано три вектора, названные соответственно A, B и C; и все эти три вектора привязаны к таблице O. Первая строка — это просто операция присваивания, где значение 42 присваивается O.A. Однако O.A является вектором, поэтому значение 42 не является единственным: это значение действительно для всех строк исходной таблицы. Envision уделяет особое внимание работе с векторами, и большинство операций с ними происходят сразу со всеми их значениями.

O — это не единственная таблица из образца набора данных. Например, в наборе данных также есть таблица PO, и с этой таблицей можно выполнить очень похожие операции.
PO.A = 42
PO.B = 5 * (1 + PO.A)
PO.C = PO.A + PO.B
Мы только что ввели вторую таблицу, и поэтому встает следующий вопрос: может ли Envision выполнять операции с несколькими таблицами одновременно? Ответ — да, но для этого потребуется приложить немного больше усилий. Обратите внимание на следующий сценарий:
O.A = 1
PO.A = O.A + 1 // НЕПРАВИЛЬНО!
Две таблицы, O и PO, не должны объединяться каким-либо образом, так как в них даже количество строк разное. Семантика такой операции была бы очень непонятной. Поэтому подобная операция недопустима в Envision, и при запуске такого сценария он не будет выполнен. Появится сообщение об ошибке.

Тем не менее, Envision имеет широкие возможности для комбинирования данных из разных таблиц, и об этом будет рассказано в следующем разделе.

Специальная таблица наименований

Таблицы, используемые Envision получают имена, однако есть исключение: таблица наименований. Мы заметили, что в коммерческой сфере при большинстве расчетов есть одна таблица, которая оказывается важнее всех остальных: список товаров / варианты / SKU / и т. д., в зависимости от рассматриваемой ситуации. В отличие от реляционных баз данных, где все таблицы являются равными, Envision относится к таблице наименований по-особому, что упрощает работу со сценариями, характерными для коммерческой деятельности.

В какой-то момент существования компании, большой или малой, ее сотрудники составляют таблицу, где перечислены все используемые товары, по одному товару в строке, а в столбцах содержится множество дополнительной информации, как статичной (например категории товара), так и динамической (например общий объем продаж за последние 5 недель). В зависимости от ситуации, в строках указываются товары, SKU, или любые другие подобные единицы продаваемой продукции. Создание такой сводной таблицы удобно во многих ситуациях: поиск неликвидных запасов, обновление цен, выделение самого ходового товара и т. д. Работая в компании розничной торговли, вы, возможно, часто сталкивались с такими таблицами.

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

Вернемся к образцу набора данных. Набор данных содержит список наименований. Предположим, нам нужно рассчитать инвентарную стоимость для каждого наименования. Если таблица наименований имеет имя Items, то это можно сделать следующим образом:
Items.Stock = Items.StockOnHand + Items.StockOnOrder
Items.StockValue = Items.TotalStock * BuyPrice
Однако в случае с таблицей наименований, и только с ней, имя таблицы можно опускать. Таким образом, сценарий на самом деле должен выглядеть следующим образом:
Stock = StockOnHand + StockOnOrder
StockValue = Stock * BuyPrice
Префикс Items. убирается, любые переменные, имя которых не содержит точку (.), скрыто ссылаются на вектор, привязанный к таблице наименований. Расчеты с использованием наименований очень часто встречаются в коммерции, поэтому такое решение на практике делает алгоритмы Envision гораздо более понятными.

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

Список примеров можно продолжить. Суть коммерции — в потоках: потоках товаров от поставщиков к клиентам; потоков денег от клиентов к поставщикам. Все подобные потоки можно разбить до элементарных строк, где каждая строка привязана к отдельному наименованию. Таким образом, в коммерции рассматриваются не просто любые таблицы, но таблицы, содержащие данные о наименованиях, и мы стремимся воплотить эту идею в Envision.

Таблица наименований имеет лишь один обязательный столбец — идентификатор наименования, — который должен называться «Id» согласно требованиям Envision. Практически все другие таблицы, загружаемые в Envision, также должны иметь собственные столбцы «Id». Мы уже говорили выше, что невозможно объединить таблицы O и PO, потому что они не были согласованы. Столбец Id, который есть в таблице наименований и в любой другое таблице, и есть тот самый «мостик», благодаря которому комбинирование таблиц становится возможным.

Проиллюстрируем эту мысль с помощью расчетов наличных средств. Предположим, что мы хотим рассчитать полученные средства за всю историю продаж и потраченные средства за всю историю продаж. Это можно сделать с помощью сценария, приведенного ниже.
CashIn = sum(O.NetAmount)
CashOut = sum(PO.NetAmount) 
CashFlow = CashIn - CashOut
Как мы видим, наименования находятся слева от оператора присваивания, а другие таблицы — справа, по крайней мере в 1-й и 2-й строках. В этом случае использование различных таблиц допустимо благодаря применению агрегатора sum(). Мы не будем рассматривать этот агрегатор подробно в настоящей статье. Скажем только, что, исходя из его названия, sum(), этот агрегатор нужен для расчета суммы всех параметров NetAmount для каждого наименования. Сопоставление наименований и заказов происходит открыто, потому что в таблицеO есть столбец Id.

Мы разложили расчет на три строки ради большей понятности. Тем не менее, сценарий можно записать в более компактном виде, не называя промежуточные переменные:
CashFlow = sum(O.NetAmount) - sum(PO.NetAmount)
Помимо суммы, Envision поддерживает все классические агрегаторы: среднее значение, минимум, максимум, медиану и т. д. Эти агрегаторы дают широкие возможности дополнения таблицы наименований описательными атрибутами, которые могут быть очень полезными при выполнении многих задач, встречающихся в коммерческой сфере. Можно создать новый вектор в таблице наименований, рассматривая другую таблицу как агрегатор, однако возможно и обратное: можно использовать вектор из таблицы наименований при выполнении расчетов привязанных к другой таблице.

Рассмотрим ситуацию, когда необходимо заново рассчитать налог на добавочную стоимость (НДС), привязанный к строкам заказа за все продажи. Для упрощения предположим, что НДС для всех наименований и для всей истории всегда рассчитывается, исходя из 20-процентной ставки. Это можно записать следующим образом:
VatRate = 0.2 // гипотеза
F = VatRate / (1 - VatRate)
O.Vat = O.NetAmount * F
Вектор VatRate естественным образом расширяется и согласовывается с таблицейO, потому что все строки заказов привязаны к одному исходному наименованию. Это расширение можно сделать более заметным, прописав фактический код:
VatRate = 0.2 // гипотеза
O.VatRate = VatRate
O.F = O.VatRate / (1 - O.VatRate)
O.Vat = O.NetAmount * O.F
В примерах выше векторы F задаются только для того, чтобы показать разложение расчета.

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

Особый статус дат

Таблица наименований — это особый случай в Envision, потому что, как мы видели, многие фундаментальные операции в коммерческой сфере тесно связаны с понятием «наименования». Однако такие операции также часто привязаны к определенной дате: все строки истории продаж имеют соответствующий параметр даты; то же самое верно для истории закупок, а также почти для всех данных, которые можно считать историческими. Вследствие важности исторических данных для коммерции, где практически все деловые операции можно представить в виде списка действий, описывающих перемещение запасов или денежных средств с указанием даты, Envision уделяет особое внимание датам в том плане, в котором они используются именно в коммерции.

Столбец Date может быть в любой таблице, так же как и канонический столбец Id. Если такой столбец Date присутствует, то таблица индексируется не только по идентификатору наименования, но и по датам. Индексация по датам очень полезна, потому что зачастую, когда к расчетам нужно применить ограничение по времени, вся история продаж, независимо от того, операции какого типа в нее входят, будет фильтроваться одинаково.

Чтобы проиллюстрировать эту мысль, вернемся к расчетам потока денежных средств. Предположим, что вместо расчета значения для всей истории, нам нужно рассчитать поток денежных средств на наименование только за последний год. Это можно сделать следующим образом:
end := max(date)
when date > end - 365
  CashFlow = sum(O.NetAmount) - sum(PO.NetAmount)
Где переменная end представляет собой ближайшую дату во всем наборе входящих данных. При условии, что end представляет собой дату, мы видим, что Envision дает возможность выполнять расчет даты, как показано в сценарии выше. Добавление требования +1 к любой дате в Envision приводит к добавлению еще одного дня к указанной дате. Таким образом, отнимая 365 дней, мы движемся назад примерно на один год.

Сценарий начинается с фильтра when, который представляет собой условие, которое считается истинным для всех строк, обработанных в данном блоке сценария. Наименования не индексируются по датам, поэтому фильтр дат не влияет на них и все наименования сохраняются в блоке when. В таблицах заказов и заказов на закупку присутствуют собственные столбцы Date, поэтому все строки, которые не соответствуют условию фильтра when, убираются из блока сценария.

Как следствие, агрегатор sum() в блоке when обрабатывает только неотфильтрованные строки, то есть те строки, которые появились менее года назад. Ниже тот же расчет выполнен с помощью промежуточных переменных, как в самом начале было сделано с примером, иллюстрирующим всю историю.
end := max(date)
when date > end - 365
  CashIn = sum(O.NetAmount)
  CashOut = sum(PO.NetAmount)
  CashFlow = CashIn - CashOut
На примере выше, возможно, лучше видно, почему мы используем оператор when в начале фильтрующего блока: все строки в этом блоке, что заметно по двум пробелам в начале 2-й, 3-й и 4-й строк подвергаются действию того же самого фильтра дат.

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