[Power BI] 静的ABC分析を実装する

# はじめに

業務で必要になりそうだったので、研究してみました。

元ネタはこちらです。

https://www.daxpatterns.com/

## ABC分析とは

Wikipediaから引用します。

https://ja.wikipedia.org/wiki/ABC%E5%88%86%E6%9E%90

:::note
ABC分析（エイビーシーぶんせき）とは「重点分析」とも呼ばれ在庫管理などで原材料、製品(商品)等の資金的重要度を分析する手法である。在庫の資産としての価値などの評価(重要度)別に段階的な管理手順を適用する。この手法は品質管理におけるパレート分析に類似している。
:::

>製造業などで何千・何万とある原材料・製品を管理運用するうえで、管理工数的にも資産運用上もより効率的に管理するために原材料・仕掛り・製品をそれぞれの所要金額の大小でクラス分けし、それぞれに異なった管理手順を適用する。その際考慮するのは単価ではなく、単価x数量の金額である。言い換えると高額の物でもほとんど動きがないものより、低価格でも大量に動く材料のほうが重要度が高いということである。 この金額を大きいほうから並べていくと最初の10〜20%の点数で所要金額の80〜90%を占める、逆に金額の低いほうは点数こそ多いがその総金額が全体に占める割合は僅かである。

## 静的なABC分類を実装する

モデリング

#### Salesテーブル

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/e6556e43-b4c2-ad21-0b7d-9b5a91d1a005.png)

#### Produstsテーブル

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/f1f81db9-4643-1ae0-923b-a3d9ab1de7f5.png)

#### リレーション

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/5442ce5c-ea52-62fa-3e1c-a0b1a1c5b1d6.png)

#### いったんテーブルをビジュアライズ

こんな感じのテーブルになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/10551257-3fd3-2df3-2464-29257ec80fe0.png)

## 新しい列を追加してABC分析

新しい列を追加していきます。

![abc_2022-02-26-11-00-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/ba3dbfbf-4eeb-5585-a351-e4c63b5f5562.png)

### 列追加

#### 累計売上

```
累計売上 = 
VAR CurrentProductSales = 'Sales'[総売上]
VAR BetterProduct =
    FILTER (
        'Sales',
        'Sales'[総売上] >= CurrentProductSales
    )
VAR Result =
    SUMX (
        BetterProduct,
        'Sales'[総売上]
    )
RETURN
    Result
```

#### 累計売上％

```
累計売上％ = 
DIVIDE (
    'Sales'[累計売上],
    SUM ( Sales[総売上] )
)
```

#### ABC分類

```
ABC分類 = 
SWITCH (
    TRUE,
    'Sales'[累計売上％] <= 0.7, "A",
    'Sales'[累計売上％] <= 0.9, "B",
    "C"
)
```

### ビジュアライズ

列を追加することで静的ABC分類が完成しました。ビジュアライズをして確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/f35c1cbd-8b4c-8a54-34b8-e228ad9151d6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/cbfe90fc-ded9-4b75-5082-0efec15d4b0f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/5293a033-2b66-cfdd-7d23-20342db56e6d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/b4031784-41bb-ab5f-0fac-d65908b852be.png)

うん、よさそう:relaxed:

## 静的ABC分類の最適化

ただしむやみに列を追加するとモデルのサイズが大きくなり、データ更新にかかる時間が増え、望ましくない動作につながる可能性があります。ABC分類の結果がほしいだけであれば、すべての列追加をひとつのコードにまとめ、モデルのサイズを小さくすることも検討したほうが良いです。

方針としては`ADDCOLUMNS`関数を変数の中で使用することでバーチャルテーブルをつくります。
そのバーチャルテーブルの中で列を明示的に作成したときと同様に累計列や累計％列を作成します。

```
最適化ABC分類 =
VAR SalesByProduct =
    ADDCOLUMNS (
        'Sales',
        "@ProdSales", [総売上]
    )
VAR CurrentSales = [総売上]
VAR BetterProducts =
    FILTER (
        SalesByProduct,
        [@ProdSales] >= CurrentSales
    )
VAR CumulatedSales =
    SUMX (
        BetterProducts,
        [@ProdSales]
    )
VAR CumulatedPct =
    DIVIDE (
        CumulatedSales,
        SUM ( Sales[総売上] )
    )
VAR ABCClass =
    SWITCH (
        TRUE,
        CumulatedPct <= 0.7, "A",
        CumulatedPct <= 0.9, "B",
        "C"
    )
RETURN
    ABCClass

```

このバージョンのコードを使用すると、モデルのサイズは小さくなります。ただし、プロダクト数が多いデータベースでは、カラムの計算に**過剰なメモリ**を必要とする場合があります。

要は適材適所ってことですね:kiss_ww:

## まとめ

DAXPatternでは3種類のABC分類が紹介されています。

- 静的ABC分類
- スナップショットABC分類
- 動的ABC分類

https://www.daxpatterns.com/

データ量や可視化したい内容で使い分ける必要がありますね。