Страницы: 1
RSS
DAX. Округление в мере с накоплением десятых долей и распределением их по временной шкале, пытаюсь округлить прогноз с минимальными потерями
 
Доброго всем времени суток.
Имею такую проблемку: есть мера прогнозирующая чего-то по временным рядам. Суть не в логике прогнозирования (она в примере сильно упрощенная), а в том что на выходе получаем для каждого периода (в данном случае месяца) дробное число, а получить нужно целое. Если округлять стандартными методами, то на достаточно малых значениях можно получить очень сильные отклонения от изначального прогноза на год. Таким образом нужно округлять с запоминанием остатка на предыдущем временном отрезке и прибавлением его к текущему и т.д.
В PQ вопрос решается без проблем. Как я решаю формулами показал в примере. А в РР чой-та то ли туплю, то ли действительно сложно.
Есть ли у кого идеи как такое сделать сразу в формуле меры на DAX?
Вот горшок пустой, он предмет простой...
 
Доброго времени суток, в Excel открыть не получилось:


идея была, изобразил в .pbix .
Единственное, нагородил мер, потому что они в виде переменных в тексте кода меры "Прогноз" почему-то не исполнялись.
И результирующая от примера отличается, потому что принимаются в расчет значения прогноза для января и февраля.
До конца не дожал, надо убегать, но не пинайте за попытку.
Изменено: genosser - 11.03.2020 17:14:43
 
genosser, странно, у меня и в О365 и в 2016 отлично открывается. И на том спасибо. Погляжу ваши идеи.
Я так то понимаю что надо ковыряться с кумулятивными мерами, но как-то даже не очень понимаю с какой стороны зайти.
Изменено: PooHkrd - 26.08.2021 19:07:17
Вот горшок пустой, он предмет простой...
 
PooHkrd попробуйте
Код
=var InFuture = MAX('Факт'[Дата])<MAX('Календарь'[Date])
var past13 = [Продажи]( DATEADD( 'Календарь'[Date], -13, MONTH ) )
var past12 = [Продажи]( DATEADD( 'Календарь'[Date], -12, MONTH ) )
return
IF( InFuture, ROUND( ( 2 * past13 + 8 * past12 ) / 10, 0), BLANK() )
 
Sapfuldog1, спасибо за участие, но так я и сам умею, поэтому и написал:
Цитата
PooHkrd написал:
Если округлять стандартными методами, то на достаточно малых значениях можно получить очень сильные отклонения от изначального прогноза на год.
Надо реализовать именно логику показанную в формулах Экселя.
Просто на таком наборе данных это не так заметно, но в реальном массиве при таком способе погрешность недопустимая и нужно именно накапливать.
Изменено: PooHkrd - 27.08.2021 10:50:53
Вот горшок пустой, он предмет простой...
 
задача непростая, ибо рекурсии в DAX нет, а ее имплементации обычно очень узконаправленные и труднопереносимые на другие задачи.
я бы советовал менять алгоритм округления, хотя бы до уровня конечный прогноз = round(сумма прогнозов - сумма предыдущих округленных прогнозов). грубее, но ошибка округления также будет смазываться.
F1 творит чудеса
 
Максим, спасибо за ответ. Попробую ваше предложение.
Вот горшок пустой, он предмет простой...
 
поясню на всякий случай свою мысль, может, кто-то будет искать по форуму, ну и самому полезно :)
Проблема как обычно многосоставная:
  • Ваша формула в Excel при переносе в DAX подразумевает, что для одной и той же меры необходимо учитывать ее значения, рассчитанные ранее. Но, так как в DAX нет перезаписываемых переменных, в нем почти невозможно реализовать алгоритм Xi=X(i-1)+n, привычный по Excel.
  • Каждое значение в DAX рассчитывается индивидуально, независимо от расчета других значений, и отдельный расчёт не имеет представления о результатах других расчётов.
  • Соответственно, если мы хотим рассчитать что-то как сумму выражений по типу Xi = SUM(X1...X(i-1)), то в этом расчете нам надо повторить расчёт всех предыдущих X.
Исходя из этого есть практически единственный workaround (по крайней мере, мне ничего не пришло в голову другого):
Цитата
Если у нас i известен и не очень большой, то можно создать формулу DAX, которая будет внутри себя создавать VAR X1, VAR X2 и так далее для всех возможных i.
Не знаю, подходит ли для вас такой вариант. Для потенциальных 12 месяцев прогноза можно заморочиться и создать 12 переменных, которые будут рассчитывать и запоминать предыдущее состояние для последующих расчетов. Но если число месяцев прогноза не ограничено, то задача таким способом не решается.

Для ограниченного числа месяцев прогноза (например, 12), решение примерно такое:
Создаем два доп.столбца в календаре:
Код
IsForecast = IF(MAX('Факт'[Дата])<'Календарь'[Date];1;0)
Код
n =
VAR _RankTable =
    CALCULATETABLE (
        VALUES ( 'Календарь'[МММ-ГГГГ] );
        'Календарь'[IsForecast] = 1;
        ALL ( 'Календарь' )
    )
VAR _n =
    RANKX ( _RankTable; 'Календарь'[МММ-ГГГГ]; 'Календарь'[МММ-ГГГГ]; ASC )
RETURN
    IF ( 'Календарь'[IsForecast] = 1; _n )

Далее вот такая мера - немного монстр:
Код
Округленный прогноз = 
VAR __CurrentN = IF(HASONEVALUE('Календарь'[n]);MAX('Календарь'[n]))
VAR __ForecastTable = CALCULATETABLE(VALUES('Календарь'[МММ-ГГГГ]); ALL('Календарь'); 'Календарь'[IsForecast]=1; 'Календарь'[n]<=__CurrentN)
VAR __1 = ROUND(CALCULATE(SUMX(__ForecastTable;[Прогноз]); 'Календарь'[n]=1); 0)
VAR __2 = ROUND(CALCULATE(SUMX(__ForecastTable;[Прогноз]); 'Календарь'[n]<=2) - __1; 0)
VAR __3 = ROUND(CALCULATE(SUMX(__ForecastTable;[Прогноз]); 'Календарь'[n]<=3) - __2 - __1; 0)
VAR __4 = ROUND(CALCULATE(SUMX(__ForecastTable;[Прогноз]); 'Календарь'[n]<=4) - __3 - __2 - __1; 0)
VAR __5 = ROUND(CALCULATE(SUMX(__ForecastTable;[Прогноз]); 'Календарь'[n]<=5) - __4 - __3 - __2 - __1; 0)
VAR __6 = ROUND(CALCULATE(SUMX(__ForecastTable;[Прогноз]); 'Календарь'[n]<=6) - __5 - __4 - __3 - __2 - __1; 0)
VAR __7 = ROUND(CALCULATE(SUMX(__ForecastTable;[Прогноз]); 'Календарь'[n]<=7) - __6 - __5 - __4 - __3 - __2 - __1; 0)
VAR __8 = ROUND(CALCULATE(SUMX(__ForecastTable;[Прогноз]); 'Календарь'[n]<=8) - __7 - __6 - __5 - __4 - __3 - __2 - __1; 0)
VAR __9 = ROUND(CALCULATE(SUMX(__ForecastTable;[Прогноз]); 'Календарь'[n]<=9) - __8 - __7 - __6 - __5 - __4 - __3 - __2 - __1; 0)
VAR __10 = ROUND(CALCULATE(SUMX(__ForecastTable;[Прогноз]); 'Календарь'[n]<=10) - __9 - __8 - __7 - __6 - __5 - __4 - __3 - __2 - __1; 0)
VAR __11 = ROUND(CALCULATE(SUMX(__ForecastTable;[Прогноз]); 'Календарь'[n]<=11) - __10 - __9 - __8 - __7 - __6 - __5 - __4 - __3 - __2 - __1; 0)
VAR __12 = ROUND(CALCULATE(SUMX(__ForecastTable;[Прогноз]); 'Календарь'[n]<=12) - __11 - __10 - __9 - __8 - __7 - __6 - __5 - __4 - __3 - __2 - __1; 0)
RETURN
SWITCH(__CurrentN; 1;__1; 2;__2; 3;__3; 4;__4; 5;__5; 6;__6; 7;__7; 8;__8; 9;__9; 10;__10; 11;__11; 12;__12)

файлы Excel и PBIX во вложении
F1 творит чудеса
 
Максим Зеленский, круто, попробую.
Изменено: PooHkrd - 25.08.2021 23:09:33
Вот горшок пустой, он предмет простой...
Страницы: 1
Наверх