Home / 関数リファレンス

REDUCE関数で「集約の統計」を攻略する

OVERVIEW はじめに ―― 「結局どういうときに使えるの?」という絶望

Excel 365の目玉機能であるLAMBDAヘルパー関数群の中でも、ひときわ異彩を放ち、かつ理解しづらいのがREDUCE関数です。

この関数の使い方として、解説書的な文脈で言えばおそらく次のような使い方が定番となるでしょう。

数式 =REDUCE(0, A1:A10, LAMBDA(acc, x, acc + x))

これを見た実務家は、間違いなくこう思うはずです。「……で、それSUMじゃダメなの?」と。

文字結合の例にしてもCONCATTEXTJOINで事足ります。わざわざ難解なLAMBDA構文を書いてまで、既存の関数で代用できる処理を行うメリットは1ミリもありません。結果として「REDUCEは使えない関数だ」とあらぬ難癖をつけられかねません。

しかし、それはREDUCEの真のポテンシャルを1%も引き出していません。既存の関数は「1つの列(配列)」をガサッと集約するのは得意ですが、「前の計算結果の状態(State)によって、次のステップの集約ルールが動的に変わる処理」に直面した瞬間、完全に全滅します。

これこそが、実務家がマクロ(VBA)に逃げるか、シート上に大量の作業列を乱造して数式破損におびえる(イライラする)最大の分岐点です。REDUCEの本質は、マクロの「ループ処理(For Each文)」を数式1行のなかに閉じ込め、データを単一の洗練された指標へ昇華させることにあります。本稿では、統計データの前処理とマーケティング分析における「REDUCEにしか解けないリアルな課題」を攻略します。

前回解説したSCAN関数と今回のREDUCE関数は、構文(引数)が全く同じ双子のような存在です。違いは出力の形にあります。

  • SCAN関数(映画のフィルム): 計算の「途中経過」をすべて配列として出力する。累積推移の可視化やグラフのデータソース作りに向く。
  • REDUCE関数(最後の1コマ): 内部でループ計算を繰り返した「最終結果の単一の値(スカラー)」のみを出力する。泥臭いローデータをギュッと凝縮し、統計分析で使える1つの指標(特徴量)に集約するのに向く。

実践例1 ― 【データ前処理】狂気のネストを撲滅する「マルチ一括置換」

STEP 1 何が実務をイライラさせるか

自由記述のアンケートデータや、Webからスクレイピングしてきた企業名簿のローデータ。統計的な集計にかける前段階として、必ず通らなければならないのが「データクレンジング(前処理)」です。

例えば、社名に含まれる「(株)」「株式会社」「有限会社」「 (全角スペース)」といった表記ゆれや不要文字を一括で消去したいとします。従来、これをExcelの数式で実現しようとすると、以下のような地獄のネスト(入れ子)を組むしかありませんでした。

Excel Formula
=SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A2, "(株)", ""), "株式会社", ""), "有限会社", ""), " ", "")

消去したい不要ノイズが10個、20個と増えるたびに、右端の閉じカッコ ) の数を数えながら、数式をどんどん肥大化させていく狂気の作業。これが数式破損の温床となり、実務家の精神を削ってきました。

STEP 2 サンプルデータと数式

シートのF列(F2:F5)に「消去したい不要文字リスト」をあらかじめ定義しておきます。この状態で、A列の汚れたテキストから不要文字を削ぎ落とした綺麗なテキスト(B列)を、REDUCE関数1行で構築します。入力前の初期状態では、B列は完全に空欄です。

A B ... F
1 ローデータ(顧客名) クレンジング後 消去不要文字リスト
2 (株)鈴木商事 東京本社 (株)
3 佐藤ロジスティクス株式会社 株式会社
4  田中コンサルティング有限会社 有限会社
5 高橋クリニック(株)  

不要文字を全消去し、かつデータ前後の残存スペースを完全にシャットアウトするため、B2セルに以下の数式を入力します(下方向へオートフィルコピー)。

B2 =TRIM(REDUCE(A2, $F$2:$F$5, LAMBDA(text, word, SUBSTITUTE(text, word, ""))))
STEP 3 数理・ロジックの解釈

数式は B2 セルにしか入力していませんが、コピーによって各行が美しく処理されます。この数式に入力されたLAMBDAの変数 textword の動きを紐解くと、REDUCEの仕組みが綺麗に脳内整理されます。

  • 初期値(第1引数): A2(ノイズまみれの元のテキスト)が、最初の text に代入されます。
  • 配列(第2引数): $F$2:$F$5 のリストから、上から順に1文字ずつ word に取り出されます。
  • LAMBDAの計算:
    1周目:SUBSTITUTE("(株)鈴木商事 東京本社", "(株)", "") → 結果:「鈴木商事 東京本社」
    2周目:この結果が次の text に引き継がれ、次のノイズ「株式会社」の置換を試みます(変化なし)。
    3周目:さらに引き継がれ、「有限会社」の置換を試みます(変化なし)。
    4周目:最後に引き継がれた状態から、全角スペース「 」を消去します。

計算結果が雪だるま式(累積적)に次のステップへ引き渡され、配列の不要文字をすべて走査し終えた後、外側の TRIM 関数が先頭や末尾に潜む残存スペース(4行目の「 田中…」の先頭など)を根こそぎ剥離します。これにより、マクロ不要・ネストなしの完璧なデータ前処理環境が1行で完成します。

A B ... F
1 ローデータ(顧客名) クレンジング後 消去不要文字リスト
2 (株)鈴木商事 東京本社 鈴木商事東京本社 (株)
3 佐藤ロジスティクス株式会社 佐藤ロジスティクス 株式会社
4  田中コンサルティング有限会社 田中コンサルティング 有限会社
5 高橋クリニック(株) 高橋クリニック  

実践例2 ― 【特徴量抽出】顧客の「連続購入最高記録」を削り出す

STEP 1 何が実務をイライラさせるか

データが綺麗になったら、次は顧客の購買行動の分析です。ECサイトやサブスクリプションサービスにおいて、顧客の定着度(ロイヤルティ)を時系列で測る際、「通算の購入月数」だけでは不十分です。「3ヶ月連続で購入してくれている顧客」と、「3ヶ月に1回しか買わない顧客」では、エンゲージメントが全く異なるからです。

統計モデリングや解約(チャーン)予測のために、顧客ごとに時系列に並んだ購買フラグ(1=購入、0=未購入)から、「過去最高で『連続何ヶ月』買い続けてくれたか(最大ストリーク数)」という特徴量を抽出したいとします。

しかし、既存のExcel関数でこれを求めようとすると、途方に暮れることになります。条件分岐が時系列の「前後の状態」に依存するため、シート上に「現在の連続数カウンター列」を何列も横に引き伸ばして作るか、VBAで複雑なFor文を書くしかありませんでした。

STEP 2 サンプルデータと数式

時系列データとして、B列~G列に1月から6月までの購買フラグが入っているテーブル(A1:H4)を用意します。右端のH列に、各顧客の「最大連続購入月数」をREDUCE関数で一発で算出します。数式を入力する前、H列はすべて空欄です。

A B C D E F G H
1 顧客ID 1月 2月 3月 4月 5月 6月 最大連続購入数
2 C001 1 1 1 0 1 1
3 C002 0 1 1 0 0 1
4 C003 1 1 1 1 1 1

この複雑なループ条件処理を1行で行うため、H2セルに以下の数式を入力します(下方向へオートフィルコピー)。前回の解説に倣い、最終出力は単一のスカラー値(数値)として安全に削り出すため、末尾を INDEX(..., 1, 2) に統一しています。

H2 =INDEX(REDUCE(HSTACK(0, 0), B2:G2, LAMBDA(state, x, LET(current, CHOOSECOLS(state, 1), max_s, CHOOSECOLS(state, 2), next_cur, IF(x=1, current+1, 0), HSTACK(next_cur, MAX(max_s, next_cur))))), 1, 2)
STEP 3 数理・ロジックの解釈(2つの状態を保持する)

一見すると呪文のような数式ですが、分解すると非常にロジカルで整然とした構造をしています。この数式の核心は、初期値に HSTACK(0, 0) という「2つの要素を持つ配列(状態)」を置いている点にあります。

REDUCEの中で、この2つの0はそれぞれ以下の役割(State)を担って時間軸(B2:G2)を走査します。

  1. 1つ目の0(左側): 「現在の連続購入数(走査中のカウンター)」
  2. 2つ目の0(右側): 「過去最高の連続購入数(マックス記録)」

LET関数の中で、現在の値をそれぞれ currentmax_s として切り出し、次の月のフラグ x を判定します。

「もし x=1(購入)なら current + 1、そうでなければ 0 にリセット」したものを next_cur とします。 空間を結合する HSTACK で「新しい現在の連続数」と、「これまでの最高記録と新しい連続数を比較した MAX(max_s, next_cur)」を結合して次の月に引き渡します。

A B C D E F G H
1 顧客ID 1月 2月 3月 4月 5月 6月 最大連続購入数
2 C001 1 1 1 0 1 1 3
3 C002 0 1 1 0 0 1 2
4 C003 1 1 1 1 1 1 6

C001の例で動きの履歴を追ってみましょう。

  • 初期値:{0, 0}
  • 1月(1):購入なのでカウンターが進む → {1, 1}
  • 2月(1):さらに進む → {2, 2}
  • 3月(1):さらに進む → {3, 3}
  • 4月(0):未購入!カウンターは 0 にリセット、最高記録の 3 は維持 → {0, 3}
  • 5月(1):再び購入、カウンター再始動 → {1, 3}
  • 6月(1):カウンターは 2 になるが、最高記録の 3 には届かない → 最終結果 {2, 3}

REDUCEの出力は最終的に {2, 3} という2つの値(1行2列の配列)になります。本当に欲しいのは右側の器に入っている「過去最高記録(3)」だけなので、数式の外側を INDEX(..., 1, 2)(配列の1行目・2列目を抽出)に指定することで、効果的に「3」という重要な分析指標だけを安全に削り出しています。

NOTE — CHOOSECOLSについて

数式内で使用している CHOOSECOLS は、Excel 365で導入された比較的新しい関数です(Excel 2019以前では使用不可)。CHOOSECOLS(state, 1) は配列 state の1列目を取り出す処理で、INDEX(state, 1, 1) で代替できます。同様に CHOOSECOLS(state, 2)INDEX(state, 1, 2) で代替可能です。

まとめ ―― REDUCE関数を使いこなすための3箇条

  1. SUMやCONCATで代用できる簡易な集計には使わない:REDUCEの真価は、既存の関数では処理できない「前の状態に依存する動的条件」や「複雑なループの隠蔽」にあります。
  2. 初期値に配列(HSTACK)を置くことで複数状態を管理できる:実践例2のように、初期値に2つ以上の器を用意すれば、「現在のカウント」と「過去の最大値」のような高度な並行処理を数式内で保持できます。
  3. 不要な出力はINDEX関数で最後にトリミングする:ループの過程で大きくなった多次元配列や、並行管理していたカウンター状態が含まれる出力から、最終的に必要な「1マス(重要指標)」だけをピンポイントで安全に削り出す設計は、セットで使うと非常に有意義です。