統計実務やマーケティング分析において、「累積値」の算出は避けて通れません。集団全体のうち「どの位置にどれくらいのデータが集中しているか」を把握するには、データを順次積み上げていくプロセスが必要不可欠だからです。
しかし、従来のExcelで累積(ランニングトータル)を計算しようとすると、以下のような数式を組むのが一般的でした。
| C2 | =SUM($B$2:B2) |
|---|
| A | B | C | |
|---|---|---|---|
| 1 | 部門 | 人数 | 累積人数 |
| 2 | A | 2 | 2 |
| 3 | B | 8 | 10 |
| 4 | C | 18 | 28 |
| 5 | D | 14 | 42 |
| 6 | E | 8 | 50 |
「始点となるセルだけを絶対参照($B$2)にし、終点側を相対参照(B2)にする」という手法は、直感的とは言い難く、Excelの初中級者がつまずく代表的なポイントです。さらに、実務運用においては以下の致命的な弱点をはらんでいます。
- 行の挿入や削除によって計算範囲が狂い、
#REF!エラーや数式の予期せぬズレを引き起こす。 - データが追加された際に、その都度数式を最下行まで手動でコピー(オートフィル)し直さなければならない。
Excel 365やExcel 2021以降に導入されたSCAN関数は、この煩わしさを根本から解決します。動的配列(スピル)に対応しているため、一番上のセルに数式を1行書くだけで、データの増減に合わせて自動で伸縮する堅牢な累積列が完成します。
NOTE — REDUCE関数との最大の違い
似た挙動を持つ関数にREDUCEがありますが、両者の違いは「映画のフィルム」か「最後の1コマ」か、という点にあります。REDUCEは計算を積み重ねた最終的な単一の値(スカラー)のみを返しますが、SCANは計算の途中経過をすべて配列として出力する性質を持ちます。そのため、累積グラフの作成や時系列分析のデータソース構築には、SCAN関数の活用が必須となります。
実践例1 ― 累積相対度数で「パレートの法則(80:20)」を一瞬であぶり出す
顧客ごとの年間購入額データ(または商品別の売上)を降順にソートしたテーブルに対して、SCAN関数を用いて「累積相対度数(全体に対する累積構成比)」を計算します。これにより、「売上の80%を占めているのは、上位何%の顧客(商品)か」というパレートの法則(ABC分析)を一発で視覚化します。
以下の見出しとデータが、シートのA列〜E列(1行目〜11行目)に入力されている状態からスタートします。
| A | B | C | D | E | |
|---|---|---|---|---|---|
| 1 | 顧客ID | ランク | 年間購入額 (円) | 相対度数 (構成比) | 累積相対度数 (SCAN) |
| 2 | C001 | 1 | 1,200,000 | ||
| 3 | C002 | 2 | 900,000 | ||
| 4 | C003 | 3 | 700,000 | ||
| 5 | C004 | 4 | 500,000 | ||
| 6 | C005 | 5 | 300,000 | ||
| 7 | C006 | 6 | 150,000 | ||
| 8 | C007 | 7 | 100,000 | ||
| 9 | C008 | 8 | 80,000 | ||
| 10 | C009 | 9 | 40,000 | ||
| 11 | C010 | 10 | 30,000 |
まず、全体の売上に対する各顧客の「相対度数(構成比)」を求めます。D2セルに以下の数式を入力します。
| D2 | =C2:C11/SUM(C2:C11) |
|---|
続いて、求めた相対度数を上から順に積み上げる「累積相対度数(累積構成比)」を算出します。E2セルにのみ、SCAN関数を用いた以下の数式を入力します。
| E2 | =SCAN(0, D2:D11, LAMBDA(acc, x, acc + x)) |
|---|
数式はそれぞれ D2 および E2
セルにしか入力していませんが、スピル機能によって自動的に最下行(D11、E11)まで展開されます。算出されたデータを確認すると、上位4名(全体の上位40%の顧客)の時点で、累積相対度数が
0.825(82.5%)に達していることがわかります。「この4名へのアプローチを最優先すべきである」という重要な経営判断が、数式1行の累積計算から即座に導き出せます。
| A | B | C | D | E | |
|---|---|---|---|---|---|
| 1 | 顧客ID | ランク | 年間購入額 (円) | 相対度数 (構成比) | 累積相対度数 (SCAN) |
| 2 | C001 | 1 | 1,200,000 | 0.3 | 0.3 |
| 3 | C002 | 2 | 900,000 | 0.225 | 0.525 |
| 4 | C003 | 3 | 700,000 | 0.175 | 0.7 |
| 5 | C004 | 4 | 500,000 | 0.125 | 0.825 |
| 6 | C005 | 5 | 300,000 | 0.075 | 0.9 |
| 7 | C006 | 6 | 150,000 | 0.0375 | 0.9375 |
| 8 | C007 | 7 | 100,000 | 0.025 | 0.9625 |
| 9 | C008 | 8 | 80,000 | 0.02 | 0.9825 |
| 10 | C009 | 9 | 40,000 | 0.01 | 0.9925 |
| 11 | C010 | 10 | 30,000 | 0.0075 | 1 |
実践例2 ― 累積最大値によるリスク評価 ―「初期値0」に潜む罠
売上推移や投資信託の基準価額など、時系列データにおいて「その時点までの過去最高値」を常に追跡し、そこからの落ち込み度合いである「ドローダウン(下落幅)」を計算します。これは、金融リスク管理やKPIモニタリングにおける最重要指標の一つ「最大ドローダウン(MDD)」を算出するためのコアデータとなります。
分析対象として、以下の累積損益テーブルを用意します。B列は各月末時点での累積損益(単月ではなく期初からの合計)です。あらかじめ累積されたデータを用いて最高値を追跡します。
| A | B | C | D | E | |
|---|---|---|---|---|---|
| 1 | 経過月 | 累積損益 (万円) | 【失敗例】最高値 (初期値0) | 【正解例】最高値 (初期値工夫) | ドローダウン |
| 2 | 1月 | -10 | |||
| 3 | 2月 | -5 | |||
| 4 | 3月 | -20 | |||
| 5 | 4月 | 5 | |||
| 6 | 5月 | 15 | |||
| 7 | 6月 | -15 |
ここで、初期値を深く考えずに 0 と設定し、以下のようにC2セルに数式を組み立ててみます。
=SCAN(0, B2:B7, LAMBDA(acc, x, MAX(acc, x)))
一見正しそうに思えますが、データに「マイナスの値(累積損益がマイナスに転じている局面)」が含まれている場合、初期値の 0
が常に勝ってしまうため、データがプラスに転じるまで過去最高値がずっと「0」で固定されるという現象が発生します。初期状態が「0」からスタートしているため、構造上必然の挙動と言えます。
| A | B | C | D | E | |
|---|---|---|---|---|---|
| 1 | 経過月 | 累積損益 (万円) | 【失敗例】 最高値 (初期値0) | 【正解例】 最高値 (初期値工夫) | ドローダウン |
| 2 | 1月 | -10 | 0 | ||
| 3 | 2月 | -5 | 0 | ||
| 4 | 3月 | -20 | 0 | ||
| 5 | 4月 | 5 | 5 | ||
| 6 | 5月 | 15 | 15 | ||
| 7 | 6月 | -15 | 15 |
【解決策】先頭データを動的に取得する数式
この問題を回避するためには、初期値として「データの先頭の値」を動的に取得・指定する必要があります。前回の解説に倣い、安全に単一のスカラー値(数値)として渡すため、INDEX関数を使って配列の1件目の要素をスマートに抽出・指定する方法を採用します。D2セルに以下の数式を入力します。
| D2 | =SCAN(INDEX(B2:B7, 1), B2:B7, LAMBDA(acc, x, MAX(acc, x))) |
|---|
| A | B | C | D | E | |
|---|---|---|---|---|---|
| 1 | 経過月 | 累積損益 (万円) | 【失敗例】 最高値 (初期値0) | 【正解例】 最高値 (初期値工夫) | ドローダウン |
| 2 | 1月 | -10 | 0 | -10 | |
| 3 | 2月 | -5 | 0 | -5 | |
| 4 | 3月 | -20 | 0 | -5 | |
| 5 | 4月 | 5 | 5 | 5 | |
| 6 | 5月 | 15 | 15 | 15 | |
| 7 | 6月 | -15 | 15 | 15 |
正しく累積最大値の推移(D列)が求まったら、最後に各時点における「実際の累積損益」から「累積最大値」を差し引くことで、ドローダウン(下落幅)を出力します。E2セルに以下の数式を入力します。
| E2 | =B2:B7 - D2# |
|---|
NOTE — スピル参照演算子 #
D2# と指定することで、D2セルからスピルしている配列全体(最高値の推移)を動的に参照できます。
| A | B | C | D | E | |
|---|---|---|---|---|---|
| 1 | 経過月 | 累積損益 (万円) | 【失敗例】 最高値 (初期値0) | 【正解例】 最高値 (初期値工夫) | ドローダウン |
| 2 | 1月 | -10 | 0 | -10 | 0 |
| 3 | 2月 | -5 | 0 | -5 | 0 |
| 4 | 3月 | -20 | 0 | -5 | -15 |
| 5 | 4月 | 5 | 5 | 5 | 0 |
| 6 | 5月 | 15 | 15 | 15 | 0 |
| 7 | 6月 | -15 | 15 | 15 | -30 |
このようにして求めたドローダウン配列(E列)に対して、さらに全体を MIN
関数で囲む(例:=MIN(E2#))だけで、データ期間内の最大リスクである「最大ドローダウン(この例では6月の -30万円)」を一発で算出できるようになります。
まとめ ―― SCAN関数を使いこなすための3箇条
- 途中の変化を追うなら「SCAN」、最終結果だけなら「REDUCE」:累積比率の推移グラフや、時系列リスク分析のデータソース作成といった「途中経過の配列」が必要なケースには
SCANが最適です。 - 初期値の「型」と「データ範囲」を見極める:計算対象にマイナスの値が含まれる可能性があるかどうかで、初期値の設計(
0にするのか、MINやINDEXで動的に持ってくるのか)の検証は必須です。 - スピルエラー(#SPILL!)のスペースを確保する:
SCANは先頭行の数式から下方向へ自動的にデータを展開します。あらかじめ展開先となる下部セルに、手入力の文字や他のデータが混入しないようなシート設計が必要です。