順位付けDAX関数「RANKX」
使い方がよくわからなくなる、順位付けに使う「RANKX」関数。
メモしておきます。
迷うのは例えばこんなケースです。
Microsoftが提供している小売データのサンプル「AdventureWorks Sales.xlsx」を使用した場合。
時系列推移を集計する際によく使うサンプルなので、製品の売り上げデータ(Sales)に日付マスターテーブル(Date)と製品情報マスターテーブル(Product)を関連付けます。

サブカテゴリ(Subcategory)ごとの売り上げ順位を付けるとします。
以下のDAX(Data Analysis Expression)式で順位を付けます。
「ALL」を使い、「Product」テーブル全体のフィルターを解除すればいいのかと思いましたが、結果は想定とは異なりました。
RANK_A = RANKX(ALL('Product'), CALCULATE(SUM('Sales'[Sales Amount])))
1位が複数出てしまいます。


「ALL」で集計対象列のみ指定
数値ではないディメンジョンに相当する複数の列が影響するからか、どういう集計を経て1位がいくつも出たのかは、辿れませんでした。
集計したい要素(列)のみ「ALL」を使って、フィルタ対象から除外することにしました。
RANK_A1 = RANKX(ALL('Product'[Subcategory]), CALCULATE(SUM('Sales'[Sales Amount])))
結果は以下の通りです。
うまくいきました。

「RELATED」で集計対象の表に追加
順位付けに使う要素(列)を1つの表(テーブル)にまとめてから順位付けするという手も使えます。
1つの表で各列を確認できます。
画面左の「データビュー」で「Sales」テーブルに、関連付けした「Product」テーブルの「Subcategry」の列を持ってきます。
「新しい列」を選び、以下の「RELATED」を使ったDAX式を記述します。
SubCateory_Related = RELATED('Product'[Subcategory])
「SubCategory_Related」列が加わります。

改めて「RANKX」を使ったDAX式を設定します。
RANK_A2 = RANKX(ALL('Sales'[SubCategory_Related]), CALCULATE(SUM('Sales'[Sales Amount])))
正しく順位が付きます。

「RANKX」で同順位をランク付け
もう少し「RANKX」をいじってみます。
同じ順位の扱いを確認するために、「Product」テーブルの「Model」の数をカウントする列を用意しました。
テーブル名は「Product2」としています。


以下のDAX式を使い、ランキングを付けてみます。
RANK_Models = RANKX(ALL('Product2'[Subcategory]), CALCULATE(COUNTA('Product2'[Model])))
同じ数字は同じ順位となり、その次は同じ順位の数だけスキップします。


「ASC」でランクを逆順
逆に順位付けをするオプション「ASC」を使ってみます。
数字が最も大きいものに最後の順位がつきます。
「RANKX」の4番目に配置するパラメータなので、今回の場合カンマ2つの後、つまり「, , ASC」と記載します。
RANK_Models_ASC = RANKX(ALL('Product2'[Subcategory]), CALCULATE(COUNTA('Product2'[Model])), , ASC)

順位を飛ばさない「Dense」
順位をスキップせず連番にするオプションが「Dense」です。
5番目のパラメータなので、「, , , Dense」と配置します。
RANK_Models_Dense = RANKX(ALL('Product2'[Subcategory]), CALCULATE(COUNTA('Product2'[Model])), , , Dense)

ALLSELECTEDで順位付け
最初の方に設定した以下のDAX式では、「Subcategory」の順位を付けています。
RANK_A2 = RANKX(ALL('Sales'[SubCategory_Related]), CALCULATE(SUM('Sales'[Sales Amount])))
「ALLSELECTED」でも同じ結果は得られます
特定の列のフィルターのみ解除する場合は、通常「ALLSELECTED」を使うことが多いと思います。
RANK_A3 = RANKX(ALLSELECTED('Sales'[SubCategory_Related]), CALCULATE(SUM('Sales'[Sales Amount])))
なお、以下の表では「マトリックス」を使っています。


サブカテゴリの前にカテゴリ列
「Subcategory」以外の列でフィルターをかけてみます。
例えば、「Category」列を先頭の置くと、「Category」ごとの順位となります。
「Category単位で処理する」というフィルターが適用されるからです。


カテゴリだけの順位
「Category」だけの集計(フィルター)にすると、「RANK_A1」と「RANK_A2」の指定は無効になり、1行ごとに順位を決めるので、すべて「1位」になってしまいます。


「Category」のフィルターを「ALLSELECTED」を使用した以下のコードで解除すると、カテゴリの順位が付きます。
RANK_A4 = RANKX(ALLSELECTED('Sales'[Category_Related]), CALCULATE(SUM('Sales'[Sales Amount])))

