テクテク日記

テクテク=テクノロジー&一歩ずつ(テクテク)

DAXの基礎_02 -DAXとフィルター

少し時間が空きましたが、前回はPower BIが簡単にレポートを作れる一方で、気を付けないと間違った結果に結びつくことを説明しました。今回はいよいよDAXの役割について紹介していきます。

DAXの役割

以前、DAXの特徴について紹介しましたが、もう一度おさらいをします。

marshal115.hatenablog.com

  • DAXはData Modelに対してビジネスに必要な指標を計算するために作られた関数
  • DAXはポータブル関数(一度定義すればどこでも使用可能)
  • DAXExcelと同じ名称の関数が数多い(SUM / AVERAGE / IF…AND…)
  • Excelはセル単位、DAXは列単位で考える
  • 最適化するために多くの労力を要する(Excel関数の感覚ではない)
  • DAXは関数言語、かつ、クエリ言語(スカラー値の算出やテーブルクエリとしても機能)
  • Power Queryとの違いは
    a) Power Query: データを整備する
    b) DAX: 整備されたデータを評価する
  • DAXはData Modelとセットで考える必要がある(実はDAXよりもData Modelのほうが重要度は高い)
  • DAXはシンプルだが、簡単ではない(マスターすることが困難)

概念的に解説していますが、DAXの特徴をほぼカバーしていると思います。

ビジネスに必要な指標を計算

「ビジネスに必要な指標を計算するための関数」というのは、BIにおける用語でメジャー(Measure)と言います。メジャーはDAX関数を組み合わせて定義された計算結果であり、一番簡単なものは[売上実績]、[粗利益率]、[販売単価]、[在庫回転率]等となります。作られたメジャーはレポート上にダイナミックに計算され、切り口別に見たい結果となってレポートを構成していきます。

メジャーの役割についてもう少し細かく見ていくと、主に以下3つのステップを辿ります。

① フィルター(Filter)

② 集計(Aggregation)

③ 計算(Calculate)

①のフィルターですが、どのような形で結果を見たいかをPower BIにある様々なフィルター機能でフィルターしていくことを意味します。例えば、ざっくりと全体数値として以下のような形式で様々な指標としてみたい場合はPower BI上では「複数の行カード」というビジュアルとして、[在庫高]、[年間売上]等をまとめて表記させておくことができます。

f:id:marshal115:20211205131300p:plain

f:id:marshal115:20211205131401p:plain

一方で、その下に時系列の売上推移を「折れ線グラフ」として追加し、左側にあるスライサー「CY」(Current Year(直近1年)の略)でフィルターさせた状態で表現することも可能となります(下図)。

f:id:marshal115:20211205131220p:plain

f:id:marshal115:20211205131607p:plain

ここで重要なことは、①フィルターはCYのような時系列を操作するスライサーだけでなく、「複数の行カード」や「折れ線グラフ」の各ビジュアルによっても実現され、「複数の行カード」では分類に関係なく、[年間売上]であれば時系列スライサー等のフィルターにも影響され、DAXで計算された1つの値として存在し、「折れ線グラフ」では[年間売上]が月別にフィルターされた状態となって、可視化されていることです。

Power BIではスライサー以外にもページレベルフィルターやビジュアルレベルフィルターが存在しており、まとめると以下のようになります。

  • ページレベル(現在or全部のページに対するフィルター)
  • ビジュアルレベル(選んだビジュアルだけに対するフィルター)
  • スライサーレベル(スライサーで各ビジュアルに対するフィルター)
  • メジャーベース(DAXで更に選択的なフィルターが可能)

前回の記事では「作ったビジュアル(チャートやテーブル)のフィルター条件を理解する」ことの重要性について話をしましたが、何度強調しても良い部分ですので、下記も併せてご参考ください。

docs.microsoft.com

②の集計(Aggregation)ですが、フィルターと似た概念であり、

データをどの粒度で見るか

として捉えて頂いて構いません。例えば、以下のマトリックスを見ると分かりやすい。この例ではグループ(A-E、U-Z等)という粒度で、[在庫数]、[在庫高]...[値引率]まで、計7個のメジャーで計算された結果を見ていることになります。

f:id:marshal115:20211205133846p:plain

f:id:marshal115:20211205134121p:plain

※Power BIにはテーブルとマトリックスという2つのビジュアルが存在しており、前者は階層(例:大分類・中分類・小分類・商品・・)を全て表示させるのに対して、後者は上表のように、「+」というボタンの中に次の階層が隠されて状態になっている

一方、グループの1つ下の階層である分類まで広げてみると、各計算指標は各分類に従ってフィルターされた結果を表示します。これが②と③の概念であり、DAXで定義された指標(メジャー)はデータの粒度(②)やフィルター条件(①)に沿ってその都度、各セル単位で計算(③)を行っているのです。

f:id:marshal115:20211205135655p:plain

ただし、最後の③(DAXで作ったメジャー)については混乱を招く原因にもなり得るため、もう少しその概念について見ていく必要があります。

DAXは既存のフィルター条件を変更できる

前回の記事では「DAXを使って正しくメジャーを記述すると、スライサーの動きに関わらず自分の期待する結果が返ってきます」と言及しました。通常、メジャーを作らずに数値列からそのままビジュアルを作った場合、スライサーやビジュアル・ページレベルでのフィルター(上記フィルターに関する項目を参照)にはある程度対応できますが、在庫数量といった

時系列ベース(例:年月)では合計できないが、それ以外の項目(商品や拠点等)で合計する必要がある

メジャー(Semi-additive measure)を作ることができません。Semi-additiveメジャーは在庫や資産残高等、スナップショット(その時点)で見る場合に必要であり、通常のExcel Pivotでは構築できないものとなります。それゆえ、このような計算が必要な人にとってはDAXの概念等をきちんと理解することが必須で、これを今から簡単に見ていきます。

下図のようなレポートがあるとします。ここで、①~③について見てみると、①はCY(直近1年)、②は①に連動し、20/04~21/03までの12ヵ月(一部非表示であるが、12ヵ月選択可能)、③は①と②の期間における在庫残高となります。

f:id:marshal115:20211205141540p:plain

ここで質問ですが、③はいつ時点の在庫数と在庫高でしょうか?この質問に答えるため、②から21/03を選択してみましょう。

f:id:marshal115:20211205142015p:plain

21/03を選択した場合、③は変わらないことに気づいたかと思います。一方、その他のビジュアルはどうでしょうか?一番左上の「複数の行カード」と「マトリックス」ビジュアル以外、全て21/03の単月としてフィルターされているのが分かります。

DAXは既存のフィルター条件を変更できる

とは、こういうことを意味します。前回「DAXの基礎_01」では、在庫数・在庫高はCY(12ヵ月)の合計値であり、21/03を選んだ場合のみ、正しい在庫高として表示されることを思い出すと、DAXを学習してマスターことは

どのような条件下においても正しい数字を表示してくれる

強力な武器を得ることになるわけです。では、21/02を選択したらどうなるのでしょうか?

f:id:marshal115:20211205142737p:plain

上図の通り、今度は21/02時点の在庫数・在庫高がフィルターされた状態となりました。それだけでなく、それ以外の指標(年間売上・粗利益率・値引率等)も全て21/02時点から遡って1年分の結果が返されているのです。

最後に21/01~21/03を3つ選択した場合はどうでしょう?

f:id:marshal115:20211205152025p:plain

ご覧の通り、「複数の行カード」と「マトリックス」は全てのメジャー(在庫数・在庫高含む)は引き続き21/03時点、あるいはYMを何も選択していない場合と同じで、それ以外のチャートは21/01~21/03までの結果を返しています。

ここでまた先ほどの

DAXは既存のフィルター条件を変更できる

を考えると、ユーザーが選択した時点から遡って○ヵ月の計算結果をダイナミックに表現できることになるわけです。

ここで少しまとめておきますと、

a) CYだけが選ばれた状態

b) CY、かつ、21/03が選ばれた状態

c) CY、かつ、21/02が選ばれた状態

d) CY、かつ、21/01~21/03までが選ばれた状態

という4つの例を見てきましたが、いずれも正しい結果を返してくれています。在庫数・在庫高についてこれら4つを総合的に考えると、実は

在庫数・在庫高は選択範囲における直近時点を常に参照し、その時点の在庫数・在庫高を表示している

ことに気づくはずです。「選択範囲」というのがポイントで、時系列ベースでメジャーを構築する際、必ず

「選択範囲」=何をフィルターしているのか

を意識する必要があります。逆に言えば、メジャーを構築できない場合や数字が正しいかどうか分からない場合、これに集中することで答えが見つかることが殆どです。なお、上記在庫数・在庫高のDAX関数は以下のように表現されます。

InvQty = CALCULATE( SUM( 'Inv'[InventoryQuantity] ), LASTDATE( 'dCalendar'[Date] ) )

InvAmt =
CALCULATE(
    SUMX(
        'Inv',
        'Inv'[InventoryQuantity] * 'Inv'[UnitPrice@Cost]
    ),
    LASTDATE( 'dCalendar'[Date] )
)

InvQty(在庫数)もInvAmt(在庫高)も概念的には同じで、以下の順番で評価されます。

  1. CALCULATEというフィルター条件を変更できる唯一のDAX関数を使用
  2. CALCULATEはその次の数式(SUM等のDAX関数や既に定義済みのメジャー)の評価を行う前、LASTDATEというタイムインテリジェンス関数を使って、選択範囲内における最終日(テーブル)を抽出
  3. InvQtyやInvAmtは2で抽出されたテーブルでまず範囲を絞り込まれ、これにSUMやSUMXで計算された在庫数・在庫高が単月数字で表示される

※なお、今回は説明しませんが、マトリックス内の数字は必ずセル単位でそれぞれ評価されます(今後紹介予定)。

まとめ

  • DAXは非常にパワフルな言語であり、その役割・特徴は冒頭に記載の通り
  • DAXはフィルターという概念とペアで考える必要があり、良いレポートを構築するためには、フィルター条件やフィルターの種類について理解する必要がある
  • DAXにおけるCALCULATEはフィルター条件を変更できる唯一の関数である