昔書いたPanel Chartに関する記事について、欠損値が生じる場合について掘り下げてみようと思います。
今回使用したWorkbookはこちらから:
欠損値があるViewにおけるPanel Chartについて
まず欠損値がある場合のPanel Chartを例示します。
下図はオーダー年月ごとのSalesを、サブカテゴリを使用したPanel Chartで作成しました。
見て分かるように、Panel Chartはサブカテゴリで綺麗にパネルを分けることが期待されているわけですが、一つのパネルに複数サブカテゴリが入りますね。端的に言えばVizが壊れています。
なぜこちらが起こるかと言うと、下図から分かるようにオーダー年月によって足りないサブカテゴリがあるからです。
サブカテゴリ x オーダー年月のViz-LODについて、組み合わせを持たないものがあるということです。
(Viz-LODとは?という方はこちらの記事の冒頭をご参照ください)
ここで復習になりますが、Panel Chartは以下の式を使用します。
Column Divider
(INDEX()-1)%(ROUND(SQRT(SIZE())))
Row Divider
INT((INDEX()-1)/(ROUND(SQRT(SIZE()))))
ここで上図から、欠損値があるオーダー年月において、サブカテゴリのINDEXの値が変動していることが分かります。
つまり本来であれば各サブカテゴリに固有のColumn/Row Dividerの値が必要であるのに対し、欠損値がある場合は固有の値を返さないことを明示しています。
ということで、欠損値がある場合に固有の値を返すためにはどうするか?ということを以下論じていきます。
1.「欠損値を表示」オプションを使用する
この方法は日付ディメンションかBinを使用する場合にのみ使用できます。
欠損値を表示オプションは、Tableau側で欠損しているマークを補完する場合があります。
しかし、そのまま使用しただけでは上手く行かないケースもあります。
例えば先ほどのPanel Chartに欠損値表示オプションを使用しても、下図のように期待した結果からは遠いままです。
これは欠損値を表示オプションでマークを補完しようとしても、欠損値はSalesを持たないため、縦軸がNULLなので結果的にマークが現れないことによります。
ところでもう一度先ほどの図に注目すると、表計算(INDEX())は欠損値についても計算が走っていることを示唆しています。
つまり表計算(ここではINDEXを使用)を使用すれば欠損値を表示オプションで保管されたマーク含めてNULLマークは原理上存在しないことになります。
(ここでNULLマークという言葉を使用しましたが、これは「値がNULLのマーク」ではなく「設定上存在が許されるがマークとして現れないマーク」を指しています。他に良い表現が思いついたら後で修正します)
(マークとはTableau用語です。簡潔に言えばグラフ上の点などですが、公式にはこちらを参照ください:https://help.tableau.com/current/pro/desktop/ja-jp/view_parts.htm)
ということで、先ほどのViewにINDEX()を入れてみましょう。
(ここで表計算のディメンションの順番が重要なのですが、基本的には欠損値表示オプションを使うディメンションを一番上にすれば上手くいくと思います。厳密な検証はしておらず、また解説は長くなるので割愛しますが・・・)
NULLマークがなくなることにより、Column/Row Dividerも欠損なく計算されるようになりました。
値が途切れ途切れなので、ZN(SUM(Sales))を縦軸にします。きれいになりました。
ということで、欠損値を表示オプションが使用できるのであれば、このNULLマークを表計算で補完する方法が一番シンプルだと思います。
2.WINDOW_MAXでINDEXの最大値を取得する
1の方法は楽とはいえ、使用できるディメンションの種類が限られます。
例えば以下のRegionように、欠損値表示オプションが使えない状況でNULLマークが生じる場合、INDEX()で補完する方法が使えません。
このような場合は、少々前提条件が必要になりますが、別のアプローチを試します。
まず先ほどのように、どのようにINDEXが振られるかを確認します。
明らかにRegionによってズレています。
しかしWestは欠損なく表示されており、この場合が理想のINDEXの振られ方だと分かります。
ここでINDEXの値に注目すると、欠損があるRegionのサブカテゴリのINDEXは、
欠損のないRegionのINDEXより小さくなることが分かります。
したがって、Panel Chartに使用したいディメンションについて欠損のない状態がViz-LODから得られるのであれば、WINDOW_MAX(INDEX)を計算することにより理想のINDEXが取得できることを示唆しています。
実際に計算してみます。
INDEXとWINDOW_MAXは表計算の方向が異なるので、INDEXは独立したフィールドで作成し後程ネストさせます。
INDEX
INDEX()
このINDEXをWINDOW_MAX()の中に入れた結果が以下です。
ただしINDEXはサブカテゴリで、WINDOW_MAX()はこの場合Regionで計算させます。
見て分かるように、WINDOW_MAXにより各RegionのサブカテゴリINDEXは固有の値を持つようになりました。
そしてこの計算を用いてPanel Chartの計算式を修正します。
ちなみにColumn/Row DividerはSIZE()も使用しますが、こちらも同様に欠損が無い状態のSIZE()を求めたいため、独立した計算フィールドを作成します。
SIZE
SIZE()
Column Divider (欠損値対応)
(WINDOW_MAX([INDEX])-1) % (ROUND(SQRT(WINDOW_MAX([SIZE]))))
Row Divider (欠損値対応)
INT((WINDOW_MAX([INDEX])-1) / (ROUND(SQRT(WINDOW_MAX([SIZE])))))
ここでWINDOW_MAXを使用しているColumn/Row Dividerは先ほどと同様に、Regionを使用し表計算を走らせます。
INDEXとSIZEはサブカテゴリを使用し表計算を走らせます。
出来上がったものが以下です。
1の議論と異なりNULLマーク補完が出来ない場合でも使用できるテクニックですが、今回のWest Regionのように欠損値が生じないパターンが必要なので、前提条件には注意といったところでしょうか。
以上で今回の本論は終わりなのですが、以下少しだけPanel ChartのINDEX振りについて述べます。
そもそもColumn/Row Dividerの値を表計算を使わずに数字アサインすればいいのではないか、という点について
要は以下のような計算式でいいのでは?ということです。
CASE [Sub-category]
WHEN 'Table' THEN 1
WHEN 'Chairs' THEN 2
WHEN...
確かにシンプルなのですがこの手法にはいくつか問題があり、例えば
Panelの並び替えが不可能:表計算であれば特定数値が大きい順に並び替えなどが容易。
フィルタに対して弱い:表計算はディメンションフィルタ等に走るので、フィルタリングされたデータに対して都度パネル位置を計算可能。
メンテナンス性が悪い:サブカテゴリの項目が増えたときにどうするのか
他のディメンションでパネルを作ることができない(サブカテゴリ固定なので)
などが挙げられます。
アドホックレポート等で1回切りなら良いかもですが、ダッシュボード用に使用するなら表計算でパネル計算した方が良いかなと思います。
(もちろん設計次第という所もありますが)
その他固定の番号を取得する方法もありますが、フィルタ等へのパネル描画のロバスト性を考えると表計算はメリットありますよ、ということで。
まとめ
Panel Chartをメインに据えましたが、今回の本質はNULLマークと欠損値のある場合のINDEXについてでした。
今回紹介した2通りの欠損値対策はそれぞれ前提条件があるものの、マスターすることによりPanel Chartに限らず表計算応用した可視化に役立てると思います。
ご質問等はTwitter, Linkedinへよろしくお願いいたします。それでは。