Tableau 表計算を理解する　③INDEX / FIRST / LAST

## 前置き
　Tableauで表計算の計算式を作っていくうえで欠かせない関数として、INDEX（）、FIRST（）、LAST（）の3つがあります。この3つの関数は少し特殊で、どういう使い道があるのかわかりづらいと思ったので簡単に整理してみました。

## 概要
　まずはINDEX() / FIRST() / LAST()がどんな関数なのか、概要を見ていきます。
**INDEX()**
　公式のHELPページには、`パーティション内の現在の行のインデックスを返します。最初の行のインデックスは 1 から始まります。`とあります。これだけではよくわからないので実際に計算式を使ってVizを作ってみました。下図のように最初の列（2013Q1）が1になっており、そこから2,3,4と1ずつ増えていっていることがわかります。また、行（カテゴリ・サブカテゴリ）が違っても同じ値になっていることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/9a477dcd-b865-e4c2-7102-00d70c0309d1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/4d775313-cca2-e4f2-85b8-960ebe9ee4e9.png)
　ちなみに上の図は`次を使用して計算`が表（横）の時の結果であり、この設定を変えることでINDEXの値も変わってきます。いくつか変えた例を下図に示しています。ここから、以下のことがわかります。

+ 表（横）：各行は独立しており、各行の一番左が1になり、列方向（左から右）に1ずつ増えていく
+ 表（下）：各列は独立しており、各列の一番上が1になり、行方向（上から下）に1ずつ増えていく
+ 表（横から下へ）：各行は連続しており、一番上の行の一番左が1になり、列方向（左から右）に1ずつ増えていく。最後の列まで来たら次の行の最初の列に行く。
+ 表（下から横へ）：各列は連続しており、一番上の行の一番左が1になり、行方向（上から下）に1ずつ増えていく。最後の行まで来たら次の列の最初の行に行く。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/8ff85e49-6101-c3f4-9590-4c80416ecd48.png)
　以上のことから自分なりの言葉でINDEX関数を説明すると、次のように言えると思います。
**INDEX()は「ある区切りの中で、何番目の項目であるか」を表し、区切りと数える順番は`次を使用して計算`の設定によって変わる**

#### FIRST()
　公式のHELPページには、`現在の行からパーティション内の最初の行までの行数を返します。`とあります。INDEX（）と同じくこれだけではよくわからないので実際に計算式を使ってVizを作ってみました。細かいところはINDEX（）と同じなので説明は省きますが以下のことがわかります。

+ 表（横）：各行は独立しており、各行の一番左が0になり、列方向（左から右）に1ずつ減っていく
+ 表（下）：各列は独立しており、各列の一番上が0になり、行方向（上から下）に1ずつ減っていく
+ 表（横から下へ）：各行は連続しており、一番上の行の一番左が0になり、列方向（左から右）に1ずつ減っていく。最後の列まで来たら次の行の最初の列に行く。
+ 表（下から横へ）：各列は連続しており、一番上の行の一番左が0になり、行方向（上から下）に1ずつ減っていく。最後の行まで来たら次の列の最初の行に行く。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/40c382c9-bca2-85fe-bd04-7a3402586842.png)
　以上のことから自分なりの言葉でFIRST関数を説明すると、次のように言えると思います。
**FIRST()は「ある区切りの中で、最初の項目（INDEX=0の項目）からどれだけオフセットしているか？」を表し、区切りと数える順番は`次を使用して計算`の設定によって変わる**
　※正確に言えば、「ある区切りの中で、どれだけオフセットすれば最初の項目（INDEX=0の項目）を示せるか」という説明の方が正しい気もしますが、分かりやすさ重視で上記の説明としました。

#### LAST()
　公式のHELPページには、`現在の行からパーティション内の最後の行までの行数を返します。`とあります。FIRST（）と対応する計算式ではありますが、これだけではよくわからないので実際に計算式を使ってVizを作ってみました。

+ 表（横）：各行は独立しており、各行の一番右が0になり、列の逆方向（右から左）に1ずつ増えていく
+ 表（下）：各列は独立しており、各列の一番下が0になり、行の逆方向（下から上）に1ずつ増えていく
+ 表（横から下へ）：各行は連続しており、一番下の行の一番上が0になり、列の逆方向（右から左）に1ずつ増えていく。最初の列まで来たら上の行の最後の列に行く。
+ 表（下から横へ）：各列は連続しており、一番下の行の一番上が0になり、行の逆方向（下から上）に1ずつ増えていく。最初の行まで来たら左の列の最後の行に行く。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/a00bdb9c-0446-2103-c7bf-fa79ad7c0b0c.png)
　以上のことから自分なりの言葉でLAST関数を説明すると、次のように言えると思います。
**LAST()は「ある区切りの中で、最後の項目（INDEXが最大となる項目）からどれだけオフセットしているか？」を表し、区切りと数える順番は`次を使用して計算`の設定によって変わる**
　※正確に言えば、「ある区切りの中で、どれだけオフセットすれば最後の項目（INDEXが最大となる項目）を示せるか」という説明の方が正しい気もしますが、分かりやすさ重視で上記の説明としました。

## どうやって使う？
　ここまでで、INDEX() / FIRST() / LAST()がどんな関数なのかわかりました。「ではさっそく活用してみましょう！」となったときに、どう使えばよいかイメージできますか？　私は最初、何に使えばよいか全然イメージできませんでした。

　答えは、**他の表計算関数と組み合わせて使う**、正確に言うと**引数としてオフセットを要求する表計算関数において、オフセット指定するときに使う** です。`引数としてオフセットを要求する表計算関数`にはLOOKUP関数やWINDOW関数があります。例としてLOOKUP関数を見てみましょう。

　下図のように、各年の利益から初年度利益を引いた、初年度との差を求めたいとします（簡易表計算で一発で出ますが、ここではあえて手動でやってみます）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/8e5bfdb7-72f0-8057-e43d-33ac872bbe8f.png)
　図にあるように、初年度利益を表す計算式を作るため、LOOKUP関数を使うことにします。LOOKUP関数は引数としてオフセットを入れてやる必要がありますが、2013年は初年度利益=自分の値なのでオフセット=0、2014年は初年度利益=前年の値なのでオフセット=-1、2015年は初年度利益=2年前の値なのでオフセット=-2といった具合になり、**全ての年で初年度利益の値を出すためには年ごとに別々のオフセット値を入れてやらねばなりません。**
　これは困ったどうしよう、となったところでよくよく見てみると、必要なオフセット値がFIRST()の結果と合致していることに気づきます。つまり、**LOOKUP関数のオフセット値として、特定の値ではなくFIRST()の結果を与えてやれば良い**のです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/36c207b7-7af2-065d-d6c0-fefa4eda66a0.png)
 初年度利益の計算式は次のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/1c22406d-cc09-a590-8ccf-af7f353e14f5.png)
　初年度利益との差ではなく最終年度利益との差を出したい場合はFIRST()をLAST()に置き換えれば可能ですし、2年目利益との差を出したい場合はFIRST()+1とすれば可能です。

　これがFIRST() / LAST()の使い方です。LOOKUP関数やWINDOW関数を使いこなす上で必須ともいえるテクニックだと思いますので覚えておいて損はないと思います。

## おまけ　INDEX() / FIRST() / LAST()の関係
　INDEX() / FIRST() / LAST()の定義からすれば当然なのですが、INDEX() / FIRST() / LAST()の間には以下の関係が成り立ちます。なので、INDEX()を使わずにFIRST()で代用したり、LAST()を使わずにSIZE()とINDEX()で代用したりといったことも実は可能です。（だからと言って実際にやるメリットは特にないですが）

+ INDEX() + FIRST() = 1
+ INDEX() + LAST() = SIZE()
+ LAST() - FIRST() + 1 = SIZE()

※しれっと`SIZE()`関数が出てきてますが、これはパーティション内の要素数、つまりINDEX()の最大値を返す関数です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/4bdbe5c6-fa84-5e5b-bb6d-4fe27a9eda8b.png)
##　
https://qiita.com/zaki_001/items/f2e7087dc3b0fa2efae8