Генератор formula
Используйте, когда колонка не разыгрывается, а вычисляется — из других колонок той же строки. Вес, который следует за ростом. ИМТ из обоих. Цена, умноженная на количество. Остаток, который нужно напечатать, а не проверить.
<gen type="formula" expr="0.75 * Height - 58 + 6 * Z" decimals="1"/>
expr= — это тот же язык, что и if=: те же операторы, те
же функции, те же имена для тех же колонок. Разница одна — куда девается ответ: if=
съедает его как «да/нет», а формула оставляет значением своей колонки.
| Атрибут | Что задаёт |
|---|---|
expr | Обязательный. Арифметика, которой эта колонка является |
decimals | Знаков после точки, 0..10. Без него значение печатается целиком |
Колонка, которая следует за другой
Настоящие данные — не набор независимых колонок: вес идёт за ростом, доход за образованием, площадь за ценой. Формула — способ это сказать:
<sequence name="Height"><gen type="number" distribution="normal" mean="170" sd="10" decimals="1"/></sequence>
<sequence name="Z"> <gen type="number" distribution="normal" mean="0" sd="1" decimals="4"/></sequence>
<sequence name="Weight"><gen type="formula" expr="0.75 * Height - 58 + 6 * Z" decimals="1"/></sequence>
<sequence name="BMI"> <gen type="formula" expr="Weight / pow(Height / 100, 2)" decimals="1"/></sequence>
<sequence name="Label"> <gen type="formula" expr="BMI > 25 ? over : normal"/></sequence>
152.3,62.1,26.8,over 187.3,73.4,20.9,normal 172.9,69.6,23.3,normal 164.9,59.8,22.0,normal 159.3,60.9,24.0,normal 157.4,63.9,25.8,over
Height разыгран, Z — шум, из-за которого связь не превращается в прямую линию,
остальные три вычислены. Z печатать не обязательно: не упоминайте колонку в
<block>, и она останется в расчёте, не попав в файл. В конфиге для data science таких
обычно несколько.
Последняя строка стоит отдельного внимания: тернарник заставляет формулу выдавать метку, а не только число — так у обучающего набора появляется целевая колонка.
Деление и остаток, который можно напечатать
Деление здесь настоящее и было таким всегда — это единственный оператор, который не может остаться целым, потому что целые числа делением не замыкаются:
<sequence name="N"> <gen type="number" value="1..20"/></sequence>
<sequence name="Half"><gen type="formula" expr="N / 2"/></sequence>
<sequence name="Rem"> <gen type="formula" expr="N % 3"/></sequence>
<sequence name="Row"> <gen type="formula" expr="_count"/></sequence>
n=15 half=7.5 rem=0 row=1 n=9 half=4.5 rem=0 row=2 n=9 half=4.5 rem=0 row=3 n=5 half=2.5 rem=2 row=4
_count и любая другая встроенная величина читаются, так что
тренд руками — это expr="100 + 0.05 * _count".
true / false, а не 1 / 0expr="BMI > 25" даёт слово true — так же, как _last, _first и любая колонка
anomaly_flag: одно написание для флага во всём движке.
Обучающему набору обычно нужна другая форма, и тернарник рядом:
<gen type="formula" expr="BMI > 25 ? 1 : 0"/>
Целые остаются целыми
Операнд, который ЯВЛЯЕТСЯ целым числом, так и несётся целым и становится дробным, только
когда об этом попросят. Поэтому формула точна везде, где точны её входы — 1000000 * 1000000 даёт верный ответ, а не округлённый, — и становится приблизительной только тогда,
когда конфиг попросил чего-то неточного. Правила те же, что и во всём языке выражений, и
выписаны в Выражениях.
0.1 + 0.2 == 0.3 — ложь, здесь и в любом другом языке, потому что у 0.1 нет точной
двоичной формы. Это честная арифметика IEEE, а не причуда движка, — но означает, что ветка,
написанная как if="A + B == 0.3", может не сработать никогда. Сравнивайте через < и >
либо сначала округляйте обе стороны.
Пустой источник даёт пустой ответ
Ячейка, которую опустошил parent= или
missing=, — это не ноль, и формула, читающая её,
выдаёт пустоту, а не выдуманное число:
<sequence name="H" parent="G.M"><gen type="number" value="170..190"/></sequence>
<sequence name="W"><gen type="formula" expr="H * 2"/></sequence>
F,, F,, M,170,340 M,172,344
Строки, где у H значения нет, оставляют пустым и W. Это то же правило, которому
следуют накопление и статистика, пропуская опустошённую
ячейку, — только с другой стороны. Оно же делает формулу безопасной поверх колонки с
missing=: пропуски остаются пропусками, а не превращаются в арифметику.
В ветке
Формула читает только свою строку, поэтому она может быть и одной из веток построчного выбора:
<case> внутри <switch> или <mix> на
любой глубине, или одной из веток <gen if="…"> последовательности. Каждая строка, которая
досталась ветке, считается из этой строки.
<tdc>
<env count="6" seed="shop" local="ru">
<sequence name="Qty"><gen type="number" value="0..4"/></sequence>
<sequence name="Total"><gen type="number" value="10..90"/></sequence>
<switch name="Each" on="Qty">
<case is="0"><data>ничего не куплено</data></case>
<default><gen type="formula" expr="Total / Qty" decimals="2"/></default>
</switch>
</env>
<block><line><data>${{Qty}},${{Total}},${{Each}}</data></line></block>
</tdc>
0,77,ничего не куплено 4,76,19.00 4,46,11.50 4,81,20.25 1,70,70.00 0,59,ничего не куплено
Total / Qty — деление на ноль на строках, где Qty равен 0, но эти строки принадлежат
другой ветке, и формулу о них не спрашивают. Та же колонка, записанная через if=, работает
так же:
<sequence name="Each">
<gen if="Qty > 0" type="formula" expr="Total / Qty" decimals="2"/>
<gen type="text" value="ничего не куплено"/>
</sequence>
_count внутри ветки — номер самой строки, как и везде. Две вещи в ветку не попадают, и
check говорит об этом кодом TDC295: формула с prev() — ей нужны
строки до неё, и она строится по порядку на весь прогон, — и любая формула как часть или поле
составной <sequence>. Посчитайте её отдельной последовательностью и вставьте в запись там,
где запись печатается.
Обёртки, которых формула не берёт
mask=, case=, missing=, missing_as=, repeat=, anomaly= и
anomaly_factor= получают отказ TDC015, а не принимаются
и игнорируются. Формула разрешается до того, как заработает слой форматирования, — то
же место, что у running и stat.
Ответ существует шагом позже и он лучше, потому что работает там, где значение ПЕЧАТАЕТСЯ:
<data>${{Weight|mask:x}}</data>
Какой слой: formula или <compute>
Оба вычисляют значение, и разделение тут не дело вкуса:
formula | математика — дроби, деление, функции, любая производная величина |
<compute> | контрольные цифры и работа с текстом — мод-11, Луна, дополнение, вырезание |
<compute> намеренно работает только с целыми, потому что контрольной цифре нужно именно
это. Написать формулу в его дереве тегов можно, и это мучительно: (x - lo) / (hi - lo)
там — полэкрана вложенности, а здесь тринадцать символов.
Что отказывает check
Всё, что нужно формуле, известно из конфига, поэтому ничего не ждёт прогона:
- нет
expr=—TDC294. Формула И ЕСТЬ своё выражение. expr=, который не разбирается —TDC294, с указанием на место.- имя, не являющееся колонкой, объявленной выше —
TDC240, тот же код, что уrunningиstatна то же правило, с подсказкойdid you mean, если имя похоже на настоящее. Это самое важное: опечатка вif=— просто слово, и ветка тихо перестаёт срабатывать, а опечатка в формуле доходит до арифметики. - формула там, где она ничего не может значить —
TDC295: формула сprev()внутри<case>или веткиif=и любая формула как часть или поле составной<sequence>. См. В ветке.
Ещё два отказа выдаёт прогон, потому что они зависят от значений, а не от конфига:
арифметика над текстовой колонкой (откуда иначе взялся бы NaN, а файл, полный NaN,
о котором никого не предупредили, хуже остановленного прогона) и деление на ноль.
Подробности
-
Читает свою строку. Строка i вычисляется из строки i и ничего больше, поэтому формула не тратит случайность — добавление её оставляет все остальные колонки на месте.
-
Порядок объявления. Формула строится из колонок, которые уже есть, поэтому каждое имя в
expr=должно принадлежать последовательности, объявленной выше. -
Она потоковая. Чтение только своей строки — ровно то, на чём построен потоковый движок, поэтому формула работает там как любая разыгранная колонка, и память не растёт вместе с числом строк. Измерено на одном конфиге: 1 млн строк — 2.1 с, 5 млн — 3.9 с, 20 млн — 9.5 с и файл на 291 МБ, при этом пик памяти вырос в 1.3 раза, пока число строк выросло в 20. Движок в памяти на тех же 5 млн занял 12.5 с и больше памяти, а до 20 млн не дотягивает вовсе.
Этим формула и отличается от накопления и статистики: тем двум нужны чужие строки — все предыдущие и вообще все, — поэтому они остаются в памяти по своему смыслу, а не по недоделке.
Смотрите также
- Выражения — операторы, функции и правила целых чисел.
- Накопление — когда ответу нужны строки до этой.
- Статистика — когда нужен весь прогон.
- Number — разыгранные колонки, которые формула читает.