はじめに
先日、JAPAN RUGBY LEAGUE ONE の開幕を記念して、選手の身長・体重をPower Queryのカスタム関数を利用してPower BI Desktopに取り込み、可視化しました。
今回取り組むこと
RANKX関数を使って身長、体重のランキングを作成します。
そのなかでRANKX関数の仕様を紐解いていきます。
作ったレポート
こんなものを作りました。
RANKX関数の構文
RANKX(<table>, <expression>[, <value>[, <order>[, <ties>]]])
身長のランキングを作成する
身長を並べるテーブルを作成します。ここにRANKX関数を書いて、ランキングをつけていきます。
200m以上の選手がこんなにいるんですね。
最低限のRANKX関数を書いてみます。1つ目の引数には身長・体重が入っているHeight&Weight
テーブルを指定して、2個めの引数は単一の結果をだす式でないといけないので、今回はMAXX関数をつかっています。
MAX_Height = MAXX('Height&Weight','Height&Weight'[Height])
datastudio HeightRank 0 = RANKX( 'Height&Weight', [MAX_Height] )
これを適用してみると↓のようになります。
期待した動きではないですよね。これは、RANKX関数が行ごとに評価をしていく仕組みになっているので、このままだと1行の中にある、1つの身長に対してランキングを返すだけの謎の関数になってしまっています。
改善1つ目
ということで、分母を表全体に変えたいと思います。そういうときはALL関数を使用します。
1つ目の引数に対してALL関数を適用して、
分母 → 表全体
分子 → 行ごとの身長
となるように書いていきます。
HeightRank 1 = RANKX(
ALL('Height&Weight'),
[MAX_Height]
)
結果
期待した結果になりました。
改善2つ目
Power BIは合計列も行もひとつとしてDAX関数の評価が行われているので注意が必要です。
いまは合計列にも数字が表示されてしまっているので、ここに数字が表示されないようにしたいです。今回はISINSCOPE関数を使用します。指定した階層にいるときだけtrue
を返します。
HeightRank 2 = IF(
ISINSCOPE( 'Height&Weight'[Name] ),
RANKX( ALL( 'Height&Weight' ), [MAX_Height] )
)
結果
期待した通り、合計行の数字がなくなりました。
改善3つ目
次に考えるのは、選手個人名のスライサーを作成して数名を選んだときに、分母が全員のママなのでランキングが直感的ではなくなっている点です。選択した選手の中でだけランキングをされるように改善します。
この場合はALLSELECTED関数を使用します。名前の通り、スライサーで選択したものすべてを分母とするときに使用します。
HeightRank 3 = IF(
ISINSCOPE( 'Height&Weight'[Name] ),
RANKX( ALLSELECTED( 'Height&Weight' ), [MAX_Height] )
)
結果
期待したとおり、5人をスライサーで選択すると、1~5位までが表示されています。
改善4つ目
レポートを作るに当たり、チームごとでのランキングも表示させたいなぁと思っています。いまの関数でチームの階層を加えると、選択したすべての選手が分母になっているので、チームをまたいでランキングが計算されています。これをチーム別にランキングが計算されるようにしていきます。
これを実現するために、ALLEXCEPT関数を使います。指定した列にかかっているフィルター以外はすべてなくなります。今回の場合、チーム名のフィルターコンテキストだけ残し、「選択した選手」フィルターは削除します。この関数を使用することで、分母がチーム全員、分子がその行の身長となり、期待したランキングを作成できます。
指定した列に適用されているフィルターを除く、テーブル内のすべてのコンテキスト フィルターを削除します。
ALLEXCEPT(<table>,<column>[,<column>[,…]])
HeightRank 4 =
IF (
ISINSCOPE ( 'Height&Weight'[Name] ),
RANKX (
ALLEXCEPT (
'Height&Weight',
'Height&Weight'[Team_Name]
),
[MAX_Height]
)
)
結果
チームごとの選手数が分母になり、ランキングされているのがわかりますね。
改善5つ目
チーム別にランキングが計算されるようになりましたが、さらにポジション別の階層も追加したいと思っています。そのときは、さきほどのALLEXCEPT関数に'Height&Weight'[Position]
カラムを追加してあげます。
HeightRank 5 =
IF (
ISINSCOPE ( 'Height&Weight'[Name] ),
RANKX (
ALLEXCEPT (
'Height&Weight',
'Height&Weight'[Position],
'Height&Weight'[Team_Name]
),
[MAX_Height]
)
)
結果
チームとポジションでフィルターをかけたときにも期待した動作になっています。
ポジションを2つ選んでもそれぞれのポジションごとにランキングが計算されています。
複数のチーム、複数のポジションを選んでも大丈夫。
まとめ
RANKX関数単体ではあまり期待したランキングは作成できなさそう。ALL関数、ALLSELECTED関数、ALLEXCEPT関数、ISINSCOPE関数などを組み合わせて状況に合わせたDAXを書いてあげることが大事。
成果物
選手のポジションごとに身長/体重を可視化できました。ランキングも機能しています。
スクラムハーフとプロップの体型の違いもばっちり可視化できています!