【VBAリファレンス】エクセル入門SCAN関数(配列にLAMBDAを適用し各中間値を返す)

スポンサーリンク

概要

Microsoft ExcelのSCAN関数は、配列(Range)に対してLAMBDA関数を適用し、各ステップにおける計算結果(中間値)を配列として返す、非常に強力な関数です。この関数は、配列の要素を順番に処理しながら、その都度得られる結果を保持したい場合に威力を発揮します。例えば、累積合計、移動平均、または特定の条件に基づいた状態遷移の追跡などに利用できます。SCAN関数は、従来のExcel関数では実現が難しかった、より複雑で動的なデータ処理を可能にします。このブログ記事では、SCAN関数の基本的な使い方から、LAMBDA関数との連携、そして実務で役立つ応用例まで、詳細に解説していきます。

詳細解説

SCAN関数は、以下の構文で構成されます。

=SCAN(初期値, 配列,LAMBDA(名前1, 名前2, 計算式))

* **初期値**: LAMBDA関数が最初に受け取る値です。これは、配列の最初の要素を処理する前の「開始点」となります。例えば、累積合計であれば0、累積積であれば1が初期値としてよく使われます。
* **配列**: LAMBDA関数を適用したいセル範囲または配列定数です。SCAN関数はこの配列の各要素を順番に処理します。
* **LAMBDA**: 2つの引数(名前1、名前2)と、それらを用いた計算式を持つ名前付き関数です。
* **名前1**: LAMBDA関数が処理する各ステップで、直前のLAMBDA関数の戻り値、または初期値を受け取ります。これは「累積値」や「状態」のようなものと捉えることができます。
* **名前2**: LAMBDA関数が処理する各ステップで、配列から取り出された現在の要素の値を受け取ります。
* **計算式**: 名前1と名前2を用いて行われる計算式です。この計算結果が、次のステップにおける名前1の値として渡されます。

SCAN関数の動作を具体的に見てみましょう。

1. SCAN関数は、まず`初期値`をLAMBDA関数の`名前1`に設定し、`配列`の最初の要素を`名前2`に設定して、`計算式`を実行します。
2. この`計算式`の戻り値が、最初の「中間値」として返されます。
3. 次に、SCAN関数は、前のステップで得られた`計算式`の戻り値(これが新しい`名前1`の値となります)と、`配列`の次の要素(これが新しい`名前2`の値となります)を用いて、再び`計算式`を実行します。
4. このプロセスが`配列`の全ての要素に対して繰り返されます。
5. 最終的に、SCAN関数は、各ステップで計算された全ての「中間値」を配列として返します。この返される配列の要素数は、`配列`の要素数と同じになります。

SCAN関数は、配列の各要素を順番に処理しながら、その「過程」を記録していくイメージです。これは、単に最終結果だけを返すSUM関数やAVERAGE関数とは異なり、処理の途中経過をすべて取得できる点が革新的です。

#### LAMBDA関数との連携

SCAN関数はLAMBDA関数と組み合わせて使用することで、その真価を発揮します。LAMBDA関数は、名前を付けずに(あるいは名前を付けて)再利用可能な関数を作成できる機能です。SCAN関数におけるLAMBDAは、配列の各要素に対してどのような処理を繰り返し適用するかを定義する「エンジン」のような役割を果たします。

例えば、以下のようなLAMBDA関数をSCAN関数内で使用できます。

* **累積合計**: `LAMBDA(acc, x, acc + x)`
* `acc`(accumulator): 直前の合計値(または初期値)
* `x`(current element): 配列の現在の要素
* `acc + x`: 直前の合計値に現在の要素を加算する
* **累積積**: `LAMBDA(acc, x, acc * x)`
* `acc`: 直前の積(または初期値)
* `x`: 配列の現在の要素
* `acc * x`: 直前の積に現在の要素を乗算する
* **移動平均**: これは少し複雑になりますが、SCAN関数と他の関数(例えばTAKEやDROP、あるいは別のLAMBDA)を組み合わせることで実現可能です。単純な移動平均であれば、直前の平均値と現在の値、そして過去の要素数から計算できます。

SCAN関数とLAMBDA関数を組み合わせることで、Excelの計算能力は飛躍的に向上し、これまでVBAや複雑な数式でしか実現できなかった処理を、よりシンプルかつ効率的に記述できるようになります。

サンプルコード

ここでは、SCAN関数とLAMBDA関数を用いた具体的なサンプルコードをいくつか紹介します。

サンプル1:累積合計の計算

A1セルからA5セルに数値が入力されていると仮定し、B列に累積合計を計算します。

=SCAN(0, A1:A5, LAMBDA(acc, x, acc + x))

この数式は、以下の動作をします。
1. 初期値 `0` を `acc` に設定します。
2. A1セルの値 `x` を使って `acc + x` (0 + A1の値) を計算します。この結果がB1セルに返されます。
3. 前の結果(B1の値)を新しい `acc` に設定し、A2セルの値 `x` を使って `acc + x` (B1の値 + A2の値) を計算します。この結果がB2セルに返されます。
4. このプロセスをA5セルまで繰り返します。
5. 結果として、B1:B5セルに累積合計が計算されます。

サンプル2:累積積の計算

A1セルからA5セルに数値が入力されていると仮定し、B列に累積積を計算します。

=SCAN(1, A1:A5, LAMBDA(acc, x, acc * x))

この数式は、累積合計と同様に動作しますが、計算式が乗算 (`*`) になっています。初期値は乗算の単位元である `1` を設定します。

サンプル3:条件付き累積合計

A1セルからA5セルに数値が入力されており、B1セルからB5セルに「達成」または「未達」といったステータスが入力されているとします。ここでは、「達成」ステータスの数値のみを累積合計していく例を示します。

例えば、A1:A5に {10, 20, 30, 40, 50}、B1:B5に {“達成”, “未達”, “達成”, “達成”, “未達”} が入っているとします。

=SCAN(0, A1:A5, LAMBDA(acc, x, IF(INDEX(B1:B5, MATCH(x, A1:A5, 0))=”達成”, acc + x, acc)))

この例では、LAMBDA関数内で `INDEX` と `MATCH` を使用して、現在の数値 `x` に対応するステータスを取得しています。そして、ステータスが「達成」であれば `acc + x` を計算し、そうでなければ `acc` をそのまま返します。これにより、「未達」の数値は累積合計に加算されません。

**注意点**: 上記の例は、A列の値が一意であることを前提としています。もしA列に重複がある場合、`MATCH` 関数は最初に見つかった行のインデックスを返すため、意図しない結果になる可能性があります。より堅牢な処理が必要な場合は、配列のインデックスを直接参照するなどの工夫が必要です。

より直接的に、配列のインデックスを処理する方法もあります。例えば、A1:A5に数値、B1:B5にステータスがある場合、以下のように記述することも可能です。

=SCAN(0, SEQUENCE(ROWS(A1:A5)), LAMBDA(acc, i, acc + IF(INDEX(B1:B5, i)=”達成”, INDEX(A1:A5, i), 0)))

この例では、`SEQUENCE(ROWS(A1:A5))` で1から行数までの連番(インデックス)を生成し、それを `i` として受け取ります。LAMBDA関数内で `INDEX` を使ってA列とB列から対応する値を取得し、条件分岐させています。

サンプル4:移動平均(例:3期間移動平均)

これはSCAN関数単体では少し複雑になるため、他の関数との組み合わせや、より高度なLAMBDAの利用が必要になります。ここでは、簡略化された例として、直前の値と現在の値の平均を計算する例を示します。

A1セルからA5セルに数値が入力されていると仮定し、B列に「直前の値と現在の値の平均」を計算します。

=SCAN(0, A1:A5, LAMBDA(acc, x, (acc + x) / 2))

この例では、`acc` は直前の計算結果(平均値)、`x` は現在の配列要素です。`acc + x` を2で割ることで、直前の平均値と現在の値の平均が計算され、それが次の `acc` となります。初期値は `0` としていますが、これは最初の要素に対してどのような値を適用したいかによって調整が必要です。

より一般的な3期間移動平均のようなものをSCAN関数で実現するには、LAMBDA関数内で配列全体を参照したり、過去の値を保持するような状態管理を工夫したりする必要があります。これは、LAMBDA関数自体が配列を引数に取れることや、LET関数と組み合わせることで可能になります。

実務アドバイス

SCAN関数は非常に強力ですが、その能力を最大限に引き出すためには、いくつかの点に注意が必要です。

1. **LAMBDA関数の理解**: SCAN関数はLAMBDA関数とセットで使われます。LAMBDA関数で「何をするか」を定義できなければ、SCAN関数を効果的に活用できません。まずはLAMBDA関数の基本的な構文と、引数の意味をしっかり理解しましょう。
2. **初期値の選定**: 初期値は、最初の計算ステップにおける「過去の値」や「状態」を表します。累積合計なら0、累積積なら1、あるいは特定の条件を満たすまでのカウントなら0など、処理内容に応じて適切な初期値を選定することが重要です。
3. **配列のサイズ**: SCAN関数は、入力配列と同じサイズの配列を返します。これにより、各ステップの結果を正確に把握できます。
4. **パフォーマンス**: 大量のデータに対してSCAN関数と複雑なLAMBDA関数を適用すると、計算に時間がかかる場合があります。パフォーマンスが問題になる場合は、処理を分割したり、より効率的なアルゴリズムを検討したりする必要があります。
5. **デバッグ**:complicatedなLAMBDA関数はデバッグが難しい場合があります。`LET` 関数と組み合わせて中間変数を定義したり、Excelの「数式の評価」機能を使ったりして、ステップごとに計算結果を確認しながら進めると良いでしょう。
6. **互換性**: SCAN関数およびLAMBDA関数は、比較的新しいExcelのバージョン(Microsoft 365やExcel 2021以降)で利用可能です。古いバージョンでは利用できないため、共有する環境に注意が必要です。
7. **可読性**: LAMBDA関数が長くなると、数式が読みにくくなることがあります。`LET` 関数を使って中間結果に名前を付けたり、コメントを付けたりするなどの工夫で、可読性を高めることが推奨されます。

SCAN関数は、以下のような実務シーンで特に役立ちます。

* **財務分析**: 過去のデータに基づいた予測値の計算、キャッシュフローの累積計算など。
* **在庫管理**: 入出庫履歴に基づいた現在の在庫数の累積計算、リードタイムの計算など。
* **プロジェクト管理**: タスクの進捗状況に基づいた全体進捗率の計算、リソースの累積使用量の計算など。
* **データ集計**: 特定の条件を満たすレコード数や合計値の累積計算。

これらの応用例を参考に、ご自身の業務でSCAN関数がどのように活用できるかを検討してみてください。

まとめ

SCAN関数は、配列に対してLAMBDA関数を適用し、各ステップの中間値を配列として返す、非常に革新的なExcel関数です。これにより、累積計算、状態遷移の追跡、移動平均の計算など、これまで複雑な数式やVBAでしか実現できなかった処理を、よりシンプルかつ効率的に記述できるようになりました。

SCAN関数を使いこなすためには、LAMBDA関数の理解、適切な初期値の設定、そして必要に応じた他の関数(LET、SEQUENCE、INDEX、MATCHなど)との組み合わせが鍵となります。Microsoft 365やExcel 2021以降のバージョンで利用可能であり、活用することで、データ分析や業務効率化の可能性を大きく広げることができます。

本記事では、SCAN関数の基本的な構文から、具体的なサンプルコード、そして実務で役立つアドバイスまでを網羅的に解説しました。ぜひ、SCAN関数をマスターして、Excelでのデータ処理能力を一段階引き上げてください。

タイトルとURLをコピーしました