《DAX圣經(jīng)》之DAX實例 簡體筆記

《DAX圣經(jīng)》第六章:DAX實例

? ? ? ? ? ? ? ? ? ------PowerBI非官方 簡體精簡筆記

? ? 計算比率與百分比

? ? ? 百分比:用一種度量的部分值去除以同一度量的總值。

? ? 第一種:銷售占總銷售額的百分比

? ? ? 包含百分比的典型報告如圖6-1所示,圖6-1一個典型的百分比報告,包含銷售額蛤肌,顯示的是絕對值和百分比。

? ? ? 在圖6-1语卤,顯示的百分比是針對總值的百分比歹鱼,即在當(dāng)前列Year和行Color條件下對總計的百分比計值。表達這種度量的規(guī)范方法是使用DIVIDE將要計算的兩個值分別作為分子分母:

[Sales %] := DIVIDE([Sales Amount],? ? ? ? ? ? ?
CALCULATE( [Sales Amount],ALLSELECTED() ))

? ? ? 該公式包含需要計算的兩個度量:一個是元度量[Sales Amount](作為分子)眨猎,一個是通過元度量加上ALLSELECTED()條件(受透視表行抑进、列、篩選器影響)的分母度量睡陪。分母處寺渗,由CALCULATE配合ALLSELECTED函數(shù)創(chuàng)建了一個新列表模型,維護了所有原始篩選(切片器和篩選器以及在透視表中的任何篩選器)兰迫。

? ? 第二種:有時信殊,不僅僅是計算銷售占總銷售額的百分比。

? ? ? 可能希望顏色列顯示在每個年份總數(shù)中所占的百分比汁果,以便生成如圖6-2所示的報告涡拘。圖6-2 在本報告中,所顯示的百分比是相對于年份的總數(shù)据德,而不是總計鳄乏。

? ? ? 這時候需要的分母度量是:計算每年的總計府蔗。跟上一個公式不同的是,只需要改變分母度量的列表篩選汞窗,以便能包含對應(yīng)的每一年,都包含當(dāng)前可見的產(chǎn)品計算赡译。我們可以通過添加Values函數(shù)輕松地完成這一任務(wù):

VALUES函數(shù)返回當(dāng)前在列表篩選中可見的所有唯一值的列值:

[Yearly %] := DIVIDE([SalesAmount],
CALCULATE([Sales Amount],ALLSELECTED(), VALUES(Date[CalendarYear] )))?

? ? ? 值得注意的是仲吏,整個CALCULATE([SalesAmount],ALLSELECTED()),就是前面公式的分母蝌焚,其實就是一個度量值列表裹唆。我們只是在該度量的基礎(chǔ)上,加了一個VALUES ( Date[CalendarYear]列表篩選條件而已只洒。其實際是一個簡潔版的CALCULATE(度量+篩選)许帐,因為與上一個公式只是分母不同”锨矗可將分母定義成度量的簡寫公式:

[Sales %01]=[Sales Amount] (ALLSELECTED())

則前面的公式也可簡寫為:
[Yearly %]:=DIVIDE([Sales Amount],
[Sales %01] ( VALUES( Date[CalendarYear] )//度量+篩選成畦。

? ? ? ? 當(dāng)CaⅠcuⅠate的第一參數(shù)引用己存在的某個度量時,可以省略CaⅠcuⅠate涝开。

? ? ? ? 通過VALUES()篩選后循帐,返回正確的結(jié)果。唯一的例外是列的總計:本例中的每一行舀武,VALUES()的結(jié)果返回了兩個可見的年份(2007與2008)拄养。到目前,我們使用了兩種模式來計算百分比的分母:(1)使用ALLSELECTED()银舱,還原原始篩選器篩選瘪匿;(2) 重新在被還原的原始篩選中定義任何新的篩選器(例如,限于當(dāng)前年份等)寻馏。

? ? 第三種:也可以應(yīng)用反向篩選模式棋弥。

? ? ? 也就是說,可以直接從原關(guān)系列表模型開始操软,而不是使用原始篩選器嘁锯,然后重新應(yīng)用篩選,結(jié)果也將相同聂薪。例如家乘,再現(xiàn)圖6 - 1中的報告,可以恢復(fù)在[Color]以及[CalendarYear]列上的篩選藏澳,而不會影響其他篩選仁锯,針對需要維護的列分別使用ALLSELECTED如:

[Yearly %] :=DIVIDE([Sales Amount],
CALCULATE([Sales Amount],
ALLSELECTED( Product[Color] ),?
ALLSELECTED( Date[CalendarYear] )))

? ? ? 還可以使用以下代碼獲得圖6-2的度量,這將只從[Color]中刪除篩選器翔悠,保持該列的篩選器不受影響:
[Yearly %-2] := DIVIDE ([SalesAmount],
CALCULATE([SalesAmount],ALLSELECTED (Product[Color] )))

? ? ? 這些度量作為示例顯示在透視表時业崖,它們都返回相同的值野芒。但是,它們之間有很大的差別双炕。事實上狞悲,這個[Yearly %]的后一版本恢復(fù)了Color上的原始篩選器,但是保留了任何其他位置的篩選器妇斤。如果篩選的列只有年份摇锋,則結(jié)果是相同的,但是站超,一旦通過日歷表中添加更多篩選器列表時荸恕,則兩個度量返回不同的值,如圖6-3所示:

? 圖6-3如果向透視表添加更多篩選器列表死相,兩種度量將返回不同的值融求。

? ? ? 正如所看到的,Yearly%返回相對于當(dāng)年的銷售百分比算撮,而Yearly%-2則返回相對于月份的銷售百分比生宛,這是因為我們將月份添加到透視表中。但這并不表示這兩個計算一個正確一個錯誤钮惠,它取決于希望計算的數(shù)值茅糜。

這里需要記住的重要一點是:

每當(dāng)計算百分比時,需要非常清楚分母是什么素挽,以及當(dāng)用戶向透視表或報表添加的更多篩選器是什么蔑赘。

計算累計總數(shù)

另一種使用頻率較高的模式,可能是累積總數(shù)模式预明。每當(dāng)有一組事務(wù)處理缩赛,并且我們有興趣在某個序列(通常是時間)上累積它們的值時,都會討論累積總計撰糠。例如:

? ? ? (1)計算一個產(chǎn)品在所有時間內(nèi)的總銷售額酥馍,以此作為累計總額;
? ? ? (2)計算一段時間內(nèi)不同客戶的總數(shù)阅酪,來作為累計值等旨袒。

? ? ? 讓我們從分析一個簡單的透視表開始,該透視表顯示了一段時間內(nèi)銷售的產(chǎn)品數(shù)量术辐⊙饩。可以在圖6 - 4中看到它:

? ? ? 圖6-4這個透視表顯示了每年和每個月銷售的產(chǎn)品總數(shù)。度量非常簡單:

[NumOfProducts] := SUM( Sales[Quantity] )

? ? ? 我們知道:此度量值計算Sales中的Quantity列數(shù)量之和辉词。它是一個元度量(即在整個數(shù)據(jù)模型下計算)必孤。因為時期表與銷售表具有一對多的關(guān)系,如果選取May 2007的值瑞躺,它將篩選銷售表敷搪,得到May 2007的銷售額兴想。這很容易。
? ? ? ? 關(guān)鍵是赡勘,如果要計算May 2007的累積總數(shù)嫂便,我們需要一個新的列表篩選條件:即篩選2007年底之前的所有期間(用于累計),而不是僅篩選May 2007闸与。? 這句話雖然很簡單顽悼,但卻隱藏了較大的復(fù)雜性。將條件分解一下:

? ? ? (1)確定當(dāng)前日期的結(jié)束時期几迄,如表示2007年底的示例;
? ? ? (2) 使用該值冰评,創(chuàng)建一個篩選器映胁,并顯示2007年底之前的所有日期。
? ? ? ? 隱藏的復(fù)雜性在于:
? ? ? (1)新的列表篩選基于當(dāng)前的列表篩選甲雅;
? ? ? (2)新的列表篩選必須大于原始篩選解孙,因為它將包含2007及更早的所有日期。

圖6-5中抛人,可以看到需要檢索的日期集弛姜,以便計算銷售產(chǎn)品的累積數(shù)量:

圖6-5所售產(chǎn)品的累計數(shù)量需要考慮到當(dāng)前產(chǎn)品在結(jié)束前的所有日期。

考慮到算法妖枚,現(xiàn)在是研究解決方案公式的時候了:
[CumulativeProducts]:=
CALCULATE(SUM(Sales[Quantity]),
FILTER(ALL('Date'),? ?
'Date'[Datekey]<=MAX('Date'[Datekey])))
? ? ? ? 這是一個標準的列表關(guān)系+篩選+條件的DAX公式廷臼,很容易解釋該公式:該度量由CALCULATE構(gòu)建的列表數(shù)據(jù)模型是:
? ? (1)SUM ( Sales[Quantity]計算列表 + ALL('Date' ) 列表 + 'Date'[Datekey]<=MAX('Date'[Datekey])(條件列表),后兩個列表構(gòu)成新的篩選列表(通過時期關(guān)系列表)绝页,篩選出計算列表計算荠商。如下簡易關(guān)系圖:

? ? ? (2)這里關(guān)鍵是要理解條件:'Date'[Datekey]<=MAX ('Date'[Datekey])⌒回憶一下MAX的確切含義“當(dāng)前篩選列表DateKey列的最大值”莱没。

? ? ? ? 一方面,因為表達式是計算篩選的一部分酷鸦,所以它仍然回到原始列表篩選中工作饰躲。例如,如果篩選May 2007臼隔,那么嘹裂,對應(yīng)的最大日期是2007年的最后一天;
? ? ? 另一方面躬翁,左邊表達式Date[DateKey] 是一個列焦蘑,意思是“當(dāng)前行篩選下的DateKey中的列值”,該列值再構(gòu)成由FILTER創(chuàng)建的“當(dāng)前列表篩選”盒发。因此例嘱,該表達式表示為:“篩選所有低于或等于(<=)May 2007最后一天的日期狡逢。這正是我們需要的條件。你可以在圖6-6中看到實際的公式計算的結(jié)果:

? ? ? ? ? 圖6-6 CumulativeProducts將值加到當(dāng)前日期拼卵。

? ? ? ? 還有一個問題是奢浑,這個公式。實際上顯示了2010年及以后的數(shù)據(jù)腋腮,而數(shù)據(jù)庫中并沒有2010的數(shù)據(jù)雀彼。而且未來所有時期的數(shù)據(jù)都將會顯示。這種行為是正確的即寡,因為我們計算的就是:今后銷售的產(chǎn)品的累計數(shù)量=迄今為止銷售的總數(shù)徊哑。盡管如此,你可能不想顯示這些數(shù)字(這種業(yè)務(wù)場景是常見的)聪富。這可以通過用空白替換不需要的行來刪除它們:

? ? (1)通過透視表表默認隱式所有值為空的行(同樣也適用于列)莺丑;
? ? (2)要隱藏不需要的行,可使用IF函數(shù)檢查當(dāng)前篩選中是否存在Sales銷售墩蔓,如下代碼所示梢莽。? ? ? ? ? ? ? ? ? ? ?

[CumulativeProducts] :=IF(COUNTROWS( Sales ) >0,

CALCULATE ( SUM( Sales[Quantity] ),
FILTER(ALL( 'Date' ),
'Date'[Datekey] <=MAX( 'Date'[Datekey]))))
? ? ? 該度量中,我們基于這樣一個事實:即IF的Else分支如果缺失奸披,將返回一個空白昏名。

計算每天與工作日的銷售額

? ? ? 另一個常用的業(yè)務(wù)場景是如何在工作日內(nèi)執(zhí)行計算的例子。這是相對于時間智能計算來說的一個簡單的場景阵面。

如圖6-7所示轻局。希望生成一個報告:

? ? ? 圖6-7在這個透視表中,可以看到銷售額分別除以天數(shù)以及工作日天數(shù)样刷。

所顯示的數(shù)字分別包含不同的含義:
? ? (1)? [endif]Sales Amount--銷售是該期間的總銷售額嗽交;
? ? (2) [endif]DailySales--? 每日銷售是每天的平均銷售。

? ? ? ? WorkDailySales是按工作日銷售的平均銷售颂斜,以及它與非工作日銷售的比例夫壁,以預(yù)計這些工作日會不會產(chǎn)生盈利。這些度量的定義如下:

[NumOfDays] := COUNTROWS(Date)?
[NumOfWorkingDays] :=CALCULATE( [NumOfDays],? Date[WorkingDay] ="WorkDay")? ?

[Sales Amount] :=SUMX( Sales, Sales[Quantity] * Sales[Unit Price] )
[DailySales] :? ? =DIVIDE( [Sales Amount],? [NumOfDays] )?

[WorkDailySales] :=DIVIDE( [SalesAmount], [NumOfWorkingDays])? --工作日天數(shù)銷售占比

? ? ? ? 這些度量很簡單沃疮,但包含了一些我們必須解決的問題盒让。事實上,在前一張圖表中司蔬,我們只篩 選了兩年:2007和2008邑茄。這些數(shù)字符合計算。為更清楚地顯示出多個年份俊啼,我們移除篩選器肺缕。如圖6-13所示。

圖6-13這個透視表的總計顯示了錯誤的值。

? ? ? 如果查看DailySales和WorkDailySales的總計同木,會立即發(fā)現(xiàn)數(shù)字是錯誤的浮梢。并不是行中顯示的值的平均值。該問題應(yīng)該很容易理解:因為在透視表中顯示的是正常天數(shù)和工作天數(shù)彤路。按總計計算時秕硝,計算的是沒有銷售的期間,而且由于天數(shù)位于分母洲尊,因而最終值低于預(yù)期远豺。我們先不看最后正確的公式,展示幾個錯誤解決方案對問題的影響坞嘀。

? ? ? 因為這兩項措施都有相同的問題躯护,所以讓集中討論DailySales,公式正確后丽涩,同時會適用于NumOfWorkingDays度量榛做。

? ? 第一次試驗:

? ? ? 你可能想到:清除掉那些沒有銷售的天數(shù)(即反利用條件,該情況在實際中經(jīng)常出現(xiàn)内狸,但這里只是提起該概念,該示例里是假反利用條件)厘擂,這很容易昆淡,可以為NumOfDays嘗試IF處理:? ? ? ? ? [NumOfDays] := IF([Sales Amount] >0,COUNTROWS(Date))

? ? ? 此更新公式使得沒有銷售的行從其中消失,看起來好了一些刽严。但它不會修正總計行昂灵。因此,這不僅是錯誤的舞萄,也具有很大的誤導(dǎo)性眨补,而且使問題不容易發(fā)現(xiàn),如圖6-8所示倒脓。

? ? ? 圖6-8 沒有銷售的期間行消失了撑螺,但總計仍然是錯誤的,

? ? ? 正如所看到的崎弃,總計仍然是錯誤的甘晤,即使沒有銷售的所有行都從透視表中消失了。是的饲做,它 們消失了:

? ? (1)一方面线婚,將NumOfDays設(shè)置為Blank,透視表將不顯示這些行盆均;
? ? (2)另一方面塞弊,在總計銷售額中,因為銷售額大于零,所以我們的公式仍然考慮了所有的日期游沿。
? ? ? 結(jié)論是:第一次實驗顯然走錯了方向饰抒。
? ? ? 這一度量存在一個明顯的問題:我們稱之為“粒度不匹配”。如果仔細看結(jié)果奏候,在月和年兩個時期粒度上都是正確的循集,只是在總計上是錯誤的。原因是:有多個年份并沒有銷售蔗草,這些沒有銷售的年份是不需要計算的咒彤。因此,我們說咒精,在年份粒度時镶柱,數(shù)字是正確的,而在總體粒度上數(shù)字是錯誤的模叙。
? ? ? ? 所以歇拆,需要解決的問題是:
? ? ? ? (1) 需要以正確的粒度計算公式;
? ? ? ? (2) 然后將結(jié)果合并為單個值范咨;
? ? ? ? (3) 并能在更高的粒度上計算這種度量故觅。

這就產(chǎn)生了一個問題:這個正確的粒度是什么?

? ? 第二次試驗:

? ? ? 需要的時期粒度在年渠啊,月输吏,日上都有可能,這取決于實際需要替蛉,雖然我們已發(fā)現(xiàn)總計的錯誤贯溅,但我們?nèi)匀粚δ甓戎蹈械綕M意,因此躲查,可以使用以下新公式將粒度設(shè)置在年份級別:

[DailySales] :=DIVIDE([Sales Amount],?
SUMX(VALUES('Date'[Calendar Year] ),
IF([Sales Amount] >0, [NumOfDays])))?

? ? ? 該公式定義的分母檢查在特定年份是否有銷售它浅。如果存在,則IF函數(shù)返回存在的天數(shù)镣煮,否則姐霍,返回一個空白,并且不會影響分母的總數(shù)典唇。值得記住的是:公式里包含的分子分母的兩種度量--Sales Amoun和NumOfDays都會正常邮弹,因為存在DAX自動隱式存在的CALCULATE。如果沒有這種CALCULATE蚓聘,公式就不能正確工作腌乡。
? ? ? ? 兩個隱式行篩選:
? ? (1)[Sales Amount]度量值列表隱式行篩選,即CALCULATE(SUM([Sales Amount]))夜牡;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (2)SUMX与纽,迭代函數(shù)自帶的隱式行篩選侣签;

? ? ? ? 在圖6-9中,可以看到結(jié)果現(xiàn)在是正確的急迂,即使在總計上也是如此:

? ? ? ? 圖6-9添加了多年份的迭代計算影所,并固定了總計。實際上僚碎,在用于這些測試的數(shù)據(jù)庫中猴娩,所有這些年都有記錄數(shù)據(jù),這意味著從1月1日到12月31日都存在數(shù)據(jù)記錄勺阐。

? ? ? 但在實際需求中卷中,你可能希望生成在幾年內(nèi)的不完全填充數(shù)據(jù)的報告。例如:在生成8月份報告時渊抽,只有到8月為止的那些數(shù)據(jù)蟆豫,而沒有8月以后并沒有的那些月的信息。

? ? ? 本例中懒闷,該度量仍將報告不正確的數(shù)字十减。因此,這項度量尚未最后確定愤估。圖6-10中帮辟,我們希望刪除掉2009年8月8之后(沒有)的銷售:

? ? ? ? 圖6-10當(dāng)一年沒有完成時,度量仍然報告不正確的結(jié)果玩焰,

? ? ? ? 可以看到由驹,8月是最后一個月(順便說一句,它是不完整的)震捣,所有高于它的總數(shù)(即季度、年份和總計)都報告了錯誤的數(shù)字闹炉。當(dāng)然這種行為是我們(有意)在代碼中使用了錯誤的粒度蒿赢,因為正確的粒度不是年份,而是月份渣触。我們使用這個年度粒度羡棵,是因為在年度水平上度量似乎是正確的。
? ? ? 但是嗅钻,即使我們確定了總計的公式皂冰,在年的粒度級一旦該年度里的某幾個月一消失,就會遇到同樣的問題养篓。既然問題在于粒度篩選不對秃流,那么。我們有了:

? ? 第三次試驗:

? ? ? 也就是柳弄,正確的度量表述式需要同時考慮到年份和月份舶胀,如:

[DailySales] :=DIVIDE([Sales Amount],
SUMX(VALUES( Date[Calendar Year] ),
SUMX(VALUES( Date[Month] ),?
IF([Sales Amount] >0, [NumOfDays]))))

? ? ? 現(xiàn)在,分母在年份和月份上執(zhí)行兩個迭代,它分別檢查每對(年份嚣伐、月份組合)是否存在該月份的銷售額糖赔,并正確地聚合出當(dāng)前存在銷售的月份的天數(shù)。圖6-11中結(jié)果:

圖6-11一旦正確設(shè)置了粒度后轩端,公式就會報告正確的數(shù)字放典。

? ? ? 第四次試驗:

使用CROSSJOIN表達式,可以更優(yōu)雅一些:
[DailySales] :=DIVIDE([Sales Amount],
SUMX(CROSSJOIN(?
VALUES( Date[Calendar Year] ),? ? ? ? ? VALUES( Date[Month] )),
IF([SalesAmount] >0, [NumOfDays])))

? ? ? ? 注意:粒度不匹配問題經(jīng)常出現(xiàn)在多個模型設(shè)計(業(yè)務(wù)場景)中基茵。

? ? ? 如果某些度量只能在定義的粒度上計算奋构,則需要迭代定義該粒度的列,最后聚合該粒度部分的結(jié)果耿导。建議詳細研究這個示例声怔,因為它將在多個數(shù)據(jù)模型中有用。
? ? ? 值得注意的是舱呻,在最近(最后)那個月里仍有一個小問題:NumOfDays的天數(shù)結(jié)果并沒有考慮到最后一個月可能不完整的情況醋火。例如,如果在8月15日提交了一份報告箱吕,就不應(yīng)該考慮到其未來的日子芥驳,因為這時候的銷售顯然是不存在的。如果還希望在最后一個月也產(chǎn)生此正確的結(jié)果茬高,需要進一步限制日期表兆旬,方法是在前面公式的后面加上一個篩選條件:刪除最后一次銷售之后的所有日期。

? ? 最后正確的度量:

? ? ? [DailySalesCorrected]:=? ?
? ? ?
CALCULATE(DIVIDE([Sales Amount],
? ? ? SUMX(
? ? ? CROSSJOIN(VALUES( Date[Calendar Year] ),VALUES( Date[Month] )),
? ? ? IF( [Sales Amount] >0, [NumOfDays] ))),? FILTER('Date', 'Date'[Date] <=MAX(Sales[OrderDate] ) ))

? ? 計算工作日差異

? ? ? 接下來是是一個非常簡單單卻非常有用的例子怎栽,因為它闡述了一種使用DAX計算值的方式丽猬,這在其他分析引擎中并不常見(比如Analysis Services多維引擎)。
? ? ? 考慮在事實表中熏瞄,對于每個訂單脚祟,有兩個這樣的日期:

? ? ? (1)OrderDate是下訂單的日期;(訂貨時期)
? ? ? (2)ShipDate? 是訂單發(fā)運的日期(發(fā)貨時期)

? ? ? ? 業(yè)務(wù)場景:計算處理訂單業(yè)務(wù)所需的天數(shù)强饮。

? ? ? ? 這很容易做到由桌,這要歸功于DAX存儲日期的方式。實際上邮丰,執(zhí)行一個簡單的減法即可:ShipDate-OrderDate就足夠能計算天數(shù)了行您。話雖如此,一些更有實際有用的數(shù)值計算是:
? ? (1)兩個日期之間的業(yè)務(wù)日天數(shù)
? ? (2)排除假日期間的工作:
? ? (3)非公司工作時的工作日天數(shù)(比如加班天數(shù))等剪廉。

? ? ? 本例娃循,使用工作日而不是非工作日來計算處理訂單的時期要公平得多。
? ? ? 事實證明斗蒋,這比簡單的減法更具挑戰(zhàn)性淮野。與前面的示例一樣捧书,日歷表包含一個列,該列定義出特定的日期:是否為工作日骤星。我們需要找到一種方法來使用該列经瓷,以計算這兩個日期之間的差異(以工作日表示)。
? ? ? 在數(shù)據(jù)模型中洞难,Calendar表用于按訂單日期舆吮、年份等對訂單進行切片。日歷和事實表之間的關(guān)系基于訂單日期队贱。為了解決這種情況色冀,需要停止將Calendar表視為維度(只用于篩選數(shù)據(jù)表),并認為Calendar表只是一個表柱嫌。使用它以不同的方式計數(shù)锋恬,而不是僅僅是維度篩選等。

? ? ? ? 例如编丘,可以在OrderDate和ShipDate之間計算Calendar表中的行數(shù)与学,這些行同時也是工作日。如果以這種方式表示該算法嘉抓,它將非乘魇兀快地通過DAX定義出計算列:

Sales[WorkinDaysHandling] = COUNTROWS(
FILTER(Date,
AND( AND(Date[Date] >= Sales[OrderDate],Date[Date] <= Sales[ShipDate]),
Date[Working Day] ="WorkDay")))? --并接第一個AND

? ? 相同算法的一種更優(yōu)雅的度量方式如下:

Sales[WorkinDaysHandling] =
CALCULATE(COUNTROWS ( Date ),
ALL(Date),
DATESBETWEEN( Date[Date], Sales[OrderDate],Sales[ShipDate]),
Date[WorkingDay] ="WorkDay")?

? ? ? 后一個公式使用了DATESBETWEEN函數(shù)構(gòu)建時期篩選:即訂貨時期與發(fā)貨時期之間的所有日期,結(jié)果是一個表抑片,然后使用它作為篩選器參數(shù)來篩選計算卵佛,以更改現(xiàn)有的WorkDay選擇。

? ? 計算靜態(tài)移動平均值

? ? ? 移動平均線是另一個常見的模式敞斋。本例提供一個如何以靜態(tài)方式計算移動平均值的示例截汪。例如,使用包含某些股票價格的股票數(shù)據(jù)模型植捎,想要計算過去50至200個期間的平均價格衙解。因為在股票市場上,一種常見的交易技巧是:觀察移動速度較快的平均線(超過50個周期)何時穿過移動到較慢的平均線(200個時段)鸥跟,以確定買入和賣出點丢郊。

? ? ? 此示例還要求盔沫,由于數(shù)據(jù)庫中的節(jié)假日遺漏日(如未確定股票價格的天數(shù)等)医咨,50個時間段與固定天數(shù)不相對應(yīng)。這就需要考慮數(shù)據(jù)庫中的遺漏日架诞,并始終確保平均50個點的股票覆蓋有一個定義的價格拟淮。
? ? ? ? 本示例使用的數(shù)據(jù)模型非常簡單,僅包含一個日歷表和另一個包含股票收盤價的表谴忧,如圖6 -12所示很泊,其中沒有1月6 - 7日兩天的價格:

? ? ? ? 圖6-12對于假期和其他非工作日角虫,股票價格有幾個遺漏。

? ? ? 為了計算平均值委造,可以添加計算列戳鹅。

? ? ? 主要原因是想要在圖表上顯示這個平均值,這意味著DAX需要計算數(shù)百個值來繪制線條昏兆。由于計算這么多平均值的點可能是一個緩慢的操作枫虏,所以,可以將這些計算合并到計算列中爬虱,以便生成更快的圖表隶债。
? ? ? 這需要定義好移動平均值起始日期,這些日期可能因股票而異跑筝。我們來解決這個問題:

? ? 第一步:給表中的每一行分配一個數(shù)字死讹。
? ? ? 這個數(shù)字隨每個股票單而增加。因此曲梗,為第一個Microsoft的價格指定一個數(shù)字:1赞警,數(shù)字2代表Microsoft的第二個價格,以此類推稀并。對Apple等每個唯一值的行都執(zhí)行同樣的操作仅颇。結(jié)果可見于圖6-19。

? ? ? ? ? 圖6-13 DayNumber列是股票價格的頻次數(shù)字碘举。
? ? 該計數(shù)只需:對與當(dāng)前行相同的每一行時期計數(shù)即可忘瓦,使用EARLIER:

Prices[DayNumber] =
COUNTROWS(FILTER(Prices,? ? ? // FILTER()表AND(Prices[Date] <=EARLIER( Prices[Date]),
Prices[Stock] =EARLIER( Prices[Stock] )))) // 同時滿足的兩個條件篩選

? ? ? 第二步:計算移動平均值。

? ? ? 既然每一行都有一個索引符引颈,就很容易確定50或200個周期的邊界:只需取當(dāng)前DayNumber--天數(shù)耕皮,減去要考慮的期間數(shù),然后取確定行的日期就足夠了蝙场。

? ? ? 可以使用兩種不同的技術(shù)來構(gòu)建這個計算列凌停。第一個方案更容易理解,即使代碼不是最優(yōu)的售滤;第二個解決方案比較優(yōu)雅一些罚拟,最大的優(yōu)點是遵循了前面概述的非常簡單的DAX計值算法規(guī)律:

Prices[MovingAverage200] =
CALCULATE ( AVERAGE(Prices[Close]),
FILTER(ALL(Prices[Date]),
AND(Prices[Date]>=LOOKUPVALUE(Prices[Date],Prices[Stock],EARLIER(Prices[Stock]),Prices[DayNumber],
EARLIER(Prices[DayNumber]) –200),
Prices[Date]<=EARLIER(Prices[Date]))),
ALLEXCEPT( Prices,Prices[Stock]))

? ? ? 該公式的核心是最內(nèi)部的條件,它篩選當(dāng)前的日期與DayNumber-200之間的日期完箩。外部ALLEXCEPT需要將計算限制為同一股票的行赐俗。
? ? ? 該公式的第二個版本是一個更好的解決方案:

Prices[MovingAverage200]=
CALCULATE (
CALCULATE ( AVERAGE(Prices[Close]),
Prices[DayNumber]>=VALUES(Prices[DayNumber])- 200,Prices[DayNumber]<=VALUES(Prices[DayNumber])),
ALLEXCEPT( Prices,Prices[Stock],Prices[DayNumber]))

? ? ? 同樣,定義出:Prices[MovingAverage50] 度量(200改為50即可)
? ? ? 這個移動平均值使用了兩個嵌套CALCULATE弊知。這里略過原內(nèi)容阻逮,其實使用DAX的萬能公式模式:關(guān)系+篩選+條件很好理解,如圖:

? ? ? 事實上秩彤,第一個紅框內(nèi):第二個CALCULATE定義的是一個度量值列表叔扼,兩個條件篩選下的求平均值的度量事哭,該度量做為第一個CALCULATE的第一個參數(shù)载矿,然后再放置了一個關(guān)系列表篩選條件(它針對ALLEXCEPT()定義的其中兩列與第二個CALCULATE()度量列表構(gòu)成新關(guān)系的計算列集峭咒,參與計算)。
? ? ? ? 三個度量很容易定義出來:
? ? ? [AVG 200] := AVERAGE( Prices[MovingAverage200] )
? ? ? [AVG 50]? := AVERAGE ( Prices[MovingAverage50] )
? ? ? [AVG Close]:= AVERAGE ( Prices[Close] )

? ? ? 最后措嵌,使用度量來顯示某個圖表与柑,該圖表為每只股票指示移動平均線交點處的買賣點流炕,如圖6-20所示:

? ? ? ? ? ? ? 圖6-20移動平均線是有用的,以顯示一個股票的隨著時間的推移方向仅胞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末每辟,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子干旧,更是在濱河造成了極大的恐慌渠欺,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件椎眯,死亡現(xiàn)場離奇詭異挠将,居然都是意外死亡,警方通過查閱死者的電腦和手機编整,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門舔稀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人掌测,你說我怎么就攤上這事内贮。” “怎么了汞斧?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵夜郁,是天一觀的道長。 經(jīng)常有香客問我粘勒,道長竞端,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任庙睡,我火速辦了婚禮事富,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘乘陪。我一直安慰自己统台,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布暂刘。 她就那樣靜靜地躺著饺谬,像睡著了一般捂刺。 火紅的嫁衣襯著肌膚如雪谣拣。 梳的紋絲不亂的頭發(fā)上募寨,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天,我揣著相機與錄音森缠,去河邊找鬼拔鹰。 笑死,一個胖子當(dāng)著我的面吹牛贵涵,可吹牛的內(nèi)容都是我干的列肢。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼宾茂,長吁一口氣:“原來是場噩夢啊……” “哼瓷马!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起跨晴,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤欧聘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后端盆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體怀骤,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年焕妙,在試婚紗的時候發(fā)現(xiàn)自己被綠了蒋伦。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡焚鹊,死狀恐怖痕届,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情末患,我是刑警寧澤爷抓,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站阻塑,受9級特大地震影響蓝撇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜陈莽,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一渤昌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧走搁,春花似錦独柑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至曲稼,卻和暖如春索绪,著一層夾襖步出監(jiān)牢的瞬間湖员,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工瑞驱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留娘摔,地道東北人。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓唤反,卻偏偏與公主長得像凳寺,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子彤侍,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容