DAX 获取倒数第 N 个非空白值

Posted

技术标签:

【中文标题】DAX 获取倒数第 N 个非空白值【英文标题】:DAX get N'th last non-blank value 【发布时间】:2021-05-13 06:04:59 【问题描述】:

对于任何给定日期,我想获得最近 3 天的平均销售额,其中包含非空白销售额。所以我不仅需要检索最后的非空白销售(这可能很容易),而且我还需要获得倒数第二和倒数第三的销售。一般来说,我需要倒数第 N 个销售。

样本数据:


+------------+--------+--------+--------+--------+------------------+
|    Date    | Amount | N'th 1 | N'th 2 | N'th 3 | Expected Results |
+------------+--------+--------+--------+--------+------------------+
| 2021-02-01 |      1 |      1 |        |        |             1.00 |
| 2021-02-02 |      2 |      2 |      1 |        |             1.50 |
| 2021-02-03 |      2 |      2 |      2 |      1 |             1.67 |
| 2021-02-04 |        |      2 |      2 |      1 |             1.67 |
| 2021-02-05 |      3 |      3 |      2 |      2 |             2.33 |
| 2021-02-06 |        |      3 |      2 |      2 |             2.33 |
| 2021-02-07 |        |      3 |      2 |      2 |             2.33 |
| 2021-02-08 |      4 |      4 |      3 |      2 |             3.00 |
| 2021-02-09 |        |      4 |      3 |      2 |             3.00 |
| 2021-02-10 |        |      4 |      3 |      2 |             3.00 |
| 2021-02-11 |        |      4 |      3 |      2 |             3.00 |
+------------+--------+--------+--------+--------+------------------+

N'th 1 是最后一次“非空白”销售。 N'th 2 是“最后一个”。预期结果是 N1、N2、N3 的平均值。

链接到示例数据文件以及接受答案建议的解决方案:DAX Rolling Average NonBlanks.pbix

【问题讨论】:

【参考方案1】:

这是我的看法(这是一个衡量标准):

Non-blank average = 
var curDate = SELECTEDVALUE(Data[Date], MAX(Data[Date]))
var nonBlankTab = FILTER(ALL(Data), NOT(ISBLANK(Data[Amount])) && Data[Date] <= curDate)
var rankedTab = FILTER ( ADDCOLUMNS ( nonBlankTab, "Rank", RANKX ( nonBlankTab, [Date] ) ), [Rank] <= 3 )
return AVERAGEX(rankedTab, [Amount])

编辑

只是一个解释:

为选定日期计算度量值。如果不存在日期上下文,则假定为最新日期。 然后我过滤掉表,只包含不迟于 curDate 的非空白销售行 然后我对日期进行排名,以便最新的 3 个日期始终获得排名 1、2 和 3。 然后我过滤掉所有排名高于 3 的日期 最后,我计算剩余 3 个数据点的平均值。

EDIT2:

我稍微简化了度量 - lastSalesDate 不是必需的。另外,根据 cmets 中的要求,我保留了第一次尝试,这是使用 TOPN 而不是 ADDCOLUMNS/RANKX/FILTER 组合的修改版本:

Non-blank average = 
var curDate = SELECTEDVALUE(Data[Date], MAX(Data[Date]))
var nonBlankTab = FILTER(ALL(Data), NOT(ISBLANK(Data[Amount])) && Data[Date] <= curDate)
var rankedTab = TOPN(3, nonBlankTab, [Date])
return AVERAGEX(rankedTab, [Amount])

EDIT3:

一个更通用的度量版本,它只是从Date 列中删除过滤器,这实际上是我们所需要的。无需屠宰桌子上的所有其他过滤器:

Non-blank average = 
var curDate = SELECTEDVALUE(Data[Date], MAX(Data[Date]))
var nonBlankTab = CALCULATETABLE(FILTER(Data, NOT(ISBLANK(Data[Amount])) && Data[Date] <= curDate), REMOVEFILTERS(Data[Date]))
var rankedTab = TOPN(3, nonBlankTab, [Date])
return AVERAGEX(rankedTab, [Amount])

【讨论】:

补充一下 - 使用这种方法,很容易计算任意数量的非空白销售的平均值,而无需引入额外的措施。当您过滤排名等于或低于 3 的表时,您只需在倒数第二步中更改一个值(或基于切片器)。 看起来非常优雅和有前途。我正在咀嚼它。 nonBlankTab 和rankedTab 是表格,不是吗? @PrzemyslawRemin 是的,它们是桌子。 第二次尝试很棒。如果您可以在回答中提及您的第一次尝试 - 我把它留在这里:VAR rankedTab = FILTER ( ADDCOLUMNS ( nonBlankTab, "Rank", RANKX ( nonBlankTab, [Date] ) ), [Rank] &lt;= 3 ) 因为它允许灵活性。如果一个人只想要第 N 个元素,他可以通过将 如何破解另一个东西——我想要这个 AVERAGE by product。我试过nonBlankTab = FILTER(ALLEXCEPT(Data, Data[product]),但它不起作用。如有任何线索,我将不胜感激。【参考方案2】:

首先,创建以下 3 个措施-

n1 = 
VAR current_date = MIN(your_table_name[Date])
VAR first_max_date_with_no_blank = 
CALCULATE(
    MAX(your_table_name[Date]),
    FILTER(ALL(your_table_name),  your_table_name[Date] <= current_date && your_table_name[Amount] <> BLANK())
)

RETURN
CALCULATE(
    SUM(your_table_name[Amount]),
    FILTER(
        ALL(your_table_name),
        your_table_name[Date] = first_max_date_with_no_blank
    )
)
n2 = 
VAR current_date = MIN(your_table_name[Date])

VAR first_max_date_with_no_blank = 
CALCULATE(
    MAX(your_table_name[Date]),
    FILTER(ALL(your_table_name),  your_table_name[Date] <= current_date && your_table_name[Amount] <> BLANK())
)

VAR second_max_date_with_no_blank = 
CALCULATE(
    MAX(your_table_name[Date]),
    FILTER(ALL(your_table_name),  your_table_name[Date] < first_max_date_with_no_blank && your_table_name[Amount] <> BLANK())
)

RETURN
CALCULATE(
    SUM(your_table_name[Amount]),
    FILTER(
        ALL(your_table_name),
        your_table_name[Date] = second_max_date_with_no_blank
    )
)
n3 = 
VAR current_date = MIN(your_table_name[Date])

VAR first_max_date_with_no_blank = 
CALCULATE(
    MAX(your_table_name[Date]),
    FILTER(ALL(your_table_name),  your_table_name[Date] <= current_date && your_table_name[Amount] <> BLANK())
)

VAR second_max_date_with_no_blank = 
CALCULATE(
    MAX(your_table_name[Date]),
    FILTER(ALL(your_table_name),  your_table_name[Date] < first_max_date_with_no_blank && your_table_name[Amount] <> BLANK())
)

VAR third_max_date_with_no_blank = 
CALCULATE(
    MAX(your_table_name[Date]),
    FILTER(ALL(your_table_name),  your_table_name[Date] < second_max_date_with_no_blank && your_table_name[Amount] <> BLANK())
)

RETURN
CALCULATE(
    SUM(your_table_name[Amount]),
    FILTER(
        ALL(your_table_name),
        your_table_name[Date] = third_max_date_with_no_blank
    )
)

现在创建这个最终度量-

average = 

VAR sum_sales = [n1] + [n2] + [n3]
VAR devide_by = IF([n1] = BLANK(),0,1) + IF([n2] = BLANK(),0,1) + IF([n3] = BLANK(),0,1)

RETURN DIVIDE(sum_sales,devide_by)

这是最终的输出-

【讨论】:

感谢您为这个答案付出的努力。这是可读的教育材料。虽然我希望解决方案更简洁。

以上是关于DAX 获取倒数第 N 个非空白值的主要内容,如果未能解决你的问题,请参考以下文章

SQL server如何获取给定月的倒数数第二天

LeetCode-019-删除链表的倒数第 N 个结点

倒数第二个值(熊猫,Python)

[算法]在单链表和双链表中删除倒数第k个结点

链表问题----删除倒数第K个节点

删除链表的倒数第n个节点(NC53/考察次数Top19/难度中等)