0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「Excel Advent Calendar 2025」3日目の記事です。

  • 学部・大学院の学生
  • 研究者
  • 社会人・教育関係者

あたりを主な読者として想定しています。


TL;DR

  • Excel は「誰でも持っている軽量なプログラミング環境」
  • .bas モジュールを 1 つ配るだけで、研究室標準の 統計・データ前処理ライブラリ を配布できる
  • ユーザー定義関数 (UDF) で
    • 重み付き平均や z スコア、ロジット変換を「セル関数」として呼べる
    • 単回帰モデルを =LinRegPredict(...) で呼べる
  • マクロで
    • 調査データのクリーニング
    • CSV エクスポート
      ワンクリック で再現可能にできる

Excel は、単なる表計算ではなく、
「軽量なデータサイエンス IDE」 として使えます、という話です。


はじめに:Excel は「全員がすでにインストールしている IDE」

理系の教育現場や研究室で学生に「プログラミング環境」を用意してもらうとき、よくぶつかる壁があります。

  • Python / R を入れようとしてつまずく
  • OS ごとに環境構築手順が違う
  • バージョン差で動かないサンプルが出る

その一方で、ほぼ全員がすでに持っている のが Excel です。

  • GUI でデータを触りながら
  • 数式で計算ロジックを記述し
  • VBA / LAMBDA / Python 連携などで自動化もできる

という意味では、Excel は

「表形式に特化した DSL (Domain Specific Language) 付きの IDE」

と見ることもできます。

本記事では、この Excel を

研究室独自の「データサイエンス用ライブラリ」

として育てるアイデアを示します。
配布単位は .bas ファイル 1 つ。
学生に配ってインポートしてもらうだけで、「研究室標準関数」が Excel に生えます。


なぜ .bas ファイルなのか?

最近の Excel には

  • FILTER
  • LET
  • LAMBDA

など、かなり強力な関数群が入りました。
これらももちろん使い倒したいのですが、複数 PC への配布バージョン差 を考えると、

  • 素の VBA モジュール (.bas)
  • ユーザー定義関数 (UDF)
  • 単純なマクロ

の組み合わせは、まだまだ現役です。

.bas で配布する利点は:

  • テキストファイルなので Git で管理しやすい
  • 研究室サーバや LMS に置いておけば、学生が簡単にダウンロードできる
  • Excel のバージョン差に比較的強い(関数名さえ気をつければ)

ということで、この記事では .bas モジュールとして

  1. 統計 / データサイエンス用 UDF 集
  2. 単回帰モデルの関数化
  3. データクリーニング + CSV エクスポートのマクロ

を作ってみます。


Step 1: 統計・データサイエンス用 UDF を追加する

まずは「よく使うけれど、毎回関数を組み立てるのは面倒」な処理を
UDF (User Defined Function) としてまとめます。

ここでは例として、以下を実装します。

  • 重み付き平均 WeightedAverage
  • z スコア ZScore
  • ロジット変換 Logit

modStatsUDF.bas の全体コード

.bas として保存できるよう、標準モジュールを丸ごと載せます。

' ===== modStatsUDF.bas =====
Option Explicit

'-----------------------------------------------
' 重み付き平均
'   =WeightedAverage(値の範囲, 重みの範囲)
'   例: =WeightedAverage(B2:B11, C2:C11)
'-----------------------------------------------
Public Function WeightedAverage(ByVal values As Range, _
                                ByVal weights As Range) As Variant
    Dim sumVW As Double
    Dim sumW As Double
    Dim c As Range
    Dim i As Long
    
    If values.Count <> weights.Count Then
        WeightedAverage = CVErr(xlErrRef)
        Exit Function
    End If
    
    i = 0
    For Each c In values.Cells
        i = i + 1
        
        If IsNumeric(c.Value) And IsNumeric(weights.Cells(i).Value) Then
            sumVW = sumVW + CDbl(c.Value) * CDbl(weights.Cells(i).Value)
            sumW = sumW + CDbl(weights.Cells(i).Value)
        End If
    Next c
    
    If sumW = 0 Then
        WeightedAverage = CVErr(xlErrDiv0)
    Else
        WeightedAverage = sumVW / sumW
    End If
End Function

'-----------------------------------------------
' zスコア
'   =ZScore(対象値, サンプル範囲)
'   例: =ZScore(A2, $A$2:$A$101)
'-----------------------------------------------
Public Function ZScore(ByVal x As Double, _
                       ByVal sampleRange As Range) As Variant
    Dim mu As Double
    Dim sigma As Double
    
    On Error GoTo ErrHandler
    
    If sampleRange.Count < 2 Then
        ZScore = CVErr(xlErrNA)
        Exit Function
    End If
    
    mu = WorksheetFunction.Average(sampleRange)
    sigma = WorksheetFunction.StDev_S(sampleRange)
    
    If sigma = 0 Then
        ZScore = CVErr(xlErrDiv0)
    Else
        ZScore = (x - mu) / sigma
    End If
    
    Exit Function
ErrHandler:
    ZScore = CVErr(xlErrValue)
End Function

'-----------------------------------------------
' ロジット変換
'   =Logit(p)
'   0 < p < 1 以外ではエラー
'   例: =Logit(0.3)
'-----------------------------------------------
Public Function Logit(ByVal p As Double) As Variant
    If p <= 0 Or p >= 1 Then
        Logit = CVErr(xlErrNum)
    Else
        Logit = WorksheetFunction.Ln(p / (1 - p))
    End If
End Function

使い方イメージ

例えば、学生の成績データが次のようにあるとします。

学籍番号 得点 単位数(重み)
A001 80 2
A002 90 1
... ... ...

このとき、重み付き平均 GPA をセルに出したければ、

=WeightedAverage(B2:B11, C2:C11)

と書くだけで済みます。

z スコアも

=ZScore(B2, $B$2:$B$101)

のように、統計教科書に出てくる記号そのまま の感覚で書けます。
Logit を使えば、ロジスティック回帰の前処理などで登場する
ロジット変換を Excel のセルの中だけで完結させることもできます。


Step 2: 単回帰モデルを Excel 関数として生やす

次に、もっとデータサイエンス寄りの例として 単回帰モデル を関数化してみます。

やりたいこと

  • 説明変数 X、目的変数 Y のデータから
    • 傾き b1
    • 切片 b0
  • さらに、新しい x_new を入力すると
    • 予測値 ŷ = b1 * x_new + b0 を返す

つまり、Excel のセルで

=LinRegSlope($A$2:$A$101, $B$2:$B$101)
=LinRegPredict(C2, $A$2:$A$101, $B$2:$B$101)

のように書けるようにします。

modRegression.bas の全体コード

' ===== modRegression.bas =====
Option Explicit

'-----------------------------------------------
' 単回帰の傾き
'   =LinRegSlope(X範囲, Y範囲)
'-----------------------------------------------
Public Function LinRegSlope(ByVal XRange As Range, _
                            ByVal YRange As Range) As Variant
    Dim coefs As Variant
    
    If XRange.Count <> YRange.Count Then
        LinRegSlope = CVErr(xlErrRef)
        Exit Function
    End If
    
    On Error GoTo ErrHandler
    ' LinEst は {傾き, 切片; …} のような配列を返す
    coefs = WorksheetFunction.LinEst(YRange, XRange, True, True)
    LinRegSlope = coefs(1, 1)
    Exit Function
    
ErrHandler:
    LinRegSlope = CVErr(xlErrValue)
End Function

'-----------------------------------------------
' 単回帰の切片
'   =LinRegIntercept(X範囲, Y範囲)
'-----------------------------------------------
Public Function LinRegIntercept(ByVal XRange As Range, _
                                ByVal YRange As Range) As Variant
    Dim coefs As Variant
    
    If XRange.Count <> YRange.Count Then
        LinRegIntercept = CVErr(xlErrRef)
        Exit Function
    End If
    
    On Error GoTo ErrHandler
    coefs = WorksheetFunction.LinEst(YRange, XRange, True, True)
    LinRegIntercept = coefs(1, 2)
    Exit Function
    
ErrHandler:
    LinRegIntercept = CVErr(xlErrValue)
End Function

'-----------------------------------------------
' 新しい X に対する予測値
'   =LinRegPredict(x, X範囲, Y範囲)
'-----------------------------------------------
Public Function LinRegPredict(ByVal x As Double, _
                              ByVal XRange As Range, _
                              ByVal YRange As Range) As Variant
    Dim b1 As Variant
    Dim b0 As Variant
    
    b1 = LinRegSlope(XRange, YRange)
    b0 = LinRegIntercept(XRange, YRange)
    
    If IsError(b1) Or IsError(b0) Then
        LinRegPredict = CVErr(xlErrValue)
    Else
        LinRegPredict = b1 * x + b0
    End If
End Function

授業・研究での使いどころ

  • 学部の実験レポートで「検量線を引いて、未知試料の濃度を推定せよ」という課題
    • X:既知濃度
    • Y:測定信号
    • LinRegSlope, LinRegIntercept, LinRegPredict線形フィットと推定をセルで再現
  • 卒論・修論の初期解析で
    「とりあえず単回帰で傾向だけ見たい」時に
    Python / R を立ち上げる前の試行錯誤用として

もちろん真面目に統計解析するなら R / Python に行くべきですが、
「とりあえずやってみて直感を掴む」 段階では、Excel のグリッドとグラフ機能は非常に強力です。


Step 3: クリーニングとエクスポートをワンクリックにする

データサイエンスの現場では、

モデルより前に、まず前処理で死ぬ

ことがよくあります。
Excel で CSV を少しだけ整えてから R / Python に渡す、というフローはよく見かけますが、

  • 空行削除
  • 文字列の前後空白削除
  • CSV エクスポート

毎回手作業でやっている と、再現性も効率も悪いです。

そこで、これらをまとめてやってくれるマクロを用意しておきます。

modDataCleaning.bas の全体コード

' ===== modDataCleaning.bas =====
Option Explicit

'-----------------------------------------------
' アクティブシートの簡易クリーニング
'   1. 2行目以降の「完全に空の行」を削除
'   2. 文字列セルの前後空白を削除
'-----------------------------------------------
Public Sub CleanSurveyData()
    Dim ws As Worksheet
    Dim lastRow As Long
    Dim lastCol As Long
    Dim r As Long
    Dim c As Long
    
    Set ws = ActiveSheet
    
    Application.ScreenUpdating = False
    
    lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
    lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
    
    ' 末尾から空行を削除(上から消すと行番号がずれるため)
    For r = lastRow To 2 Step -1
        If Application.WorksheetFunction.CountA(ws.Rows(r)) = 0 Then
            ws.Rows(r).Delete
        End If
    Next r
    
    ' 空行削除後の最終行を取り直し
    lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
    
    ' 文字列セルの前後空白を削除
    For r = 2 To lastRow
        For c = 1 To lastCol
            With ws.Cells(r, c)
                If VarType(.Value) = vbString Then
                    .Value = Trim(.Value)
                End If
            End With
        Next c
    Next r
    
    Application.ScreenUpdating = True
End Sub

'-----------------------------------------------
' アクティブシートをUTF-8のCSVとしてエクスポート
'   ・ファイル名: シート名_yyyymmdd_HHMMSS.csv
'   ・元ブックはそのまま
'-----------------------------------------------
Public Sub ExportCurrentSheetAsCsv()
    Dim ws As Worksheet
    Dim filePath As String
    Dim tempBook As Workbook
    
    Set ws = ActiveSheet
    
    If ThisWorkbook.Path = "" Then
        MsgBox "まずブックを保存してください。", vbExclamation
        Exit Sub
    End If
    
    filePath = ThisWorkbook.Path & "\" & _
               ws.Name & "_" & Format(Now, "yyyymmdd_HHMMSS") & ".csv"
    
    Application.ScreenUpdating = False
    
    ' シートだけを別ブックにコピーしてから保存
    ws.Copy
    Set tempBook = ActiveWorkbook
    tempBook.SaveAs Filename:=filePath, FileFormat:=xlCSVUTF8
    tempBook.Close SaveChanges:=False
    
    Application.ScreenUpdating = True
    
    MsgBox "CSVを書き出しました:" & vbCrLf & filePath, vbInformation
End Sub

実運用のイメージ

  1. Web フォームや Google フォームから CSV をダウンロード
  2. Excel で開く
  3. リボンに「クイックアクセスツールバー」をカスタマイズし、
    • CleanSurveyData
    • ExportCurrentSheetAsCsv
      をボタンとして配置
  4. ボタンをポチッとすると
    • 余計な空行や空白が消え
    • 一定の命名規則に沿った CSV が書き出される

この CSV をそのまま R / Python のスクリプトに食わせれば、

「Excel でちょっと整える → スクリプトで解析 → 図表をレポートに貼る」

という 再現可能なパイプライン が簡単に作れます。


.bas ファイルとして配布・再利用する手順

上で示した 3 つのモジュール

  • modStatsUDF.bas
  • modRegression.bas
  • modDataCleaning.bas

を研究室や授業で配布する場合の手順です。

1. 教員側:.bas として保存

  1. Excel で Alt + F11 を押して VBA エディタを開く
  2. 「挿入」→「標準モジュール」でモジュールを追加
  3. この記事のコードを丸ごとコピペする
  4. プロジェクトエクスプローラで対象モジュールを右クリック
  5. 「ファイルのエクスポート」で .bas として保存
    例: modStatsUDF.bas など

保存した .bas

  • GitHub / GitLab などのリポジトリ
  • 研究室の共有フォルダ
  • LMS (Moodle / Google Classroom など)

に置いておきます。

2. 学生・利用者側:インポート

  1. .bas ファイルをダウンロード
  2. Excel でブックを開き、Alt + F11 で VBA エディタへ
  3. プロジェクトエクスプローラ上で
    • 目的のブックを選択し右クリック
    • 「ファイルのインポート」から .bas を選択
  4. 元の Excel に戻ると、セルで
    • =WeightedAverage(...)
    • =ZScore(...)
    • =LinRegPredict(...)
      がそのまま使えるようになっています

これだけで

「研究室標準の関数群を、どの学生の Excel にも再現」

できるようになります。


関数 (LET / LAMBDA) や Python との相性

本記事は VBA 中心でしたが、近年の Excel では

  • LET で数式内に変数を導入
  • LAMBDA で数式ベースの関数を作成
  • Python 連携 (環境によっては Excel から直接 Python が呼べる)

といった発展も進んでいます。

個人的には、次のような使い分けがしっくりきます。

  • VBA (.bas)
    • 研究室全体・授業全体で共有したい「標準ライブラリ」
    • ファイル操作や UI 操作(ボタンなど)を伴うワークフロー
  • LAMBDA
    • そのブック内だけで完結するロジック
    • 他者の環境依存を避けたいとき(マクロ無効の環境など)
  • Python / R
    • 本格的な統計モデリング・機械学習
    • 大規模データ / 高度な可視化

Excel を 窓口 として使いつつ、段階的に外部ツールへ接続していくと、学生にとっての学習コストも抑えやすくなります。


まとめ

  • Excel は「表計算ソフト」であると同時に、誰もが持っている プログラミング環境 でもある
  • .bas モジュールを 1 つ配るだけで
    • 統計・データサイエンス向け UDF
    • 単回帰モデルの関数
    • データクリーニング & CSV エクスポート
      を研究室・授業の標準機能として配布できる
  • これにより、Excel が
    • 手作業の道具 から
    • 再現可能なワークフローを記述するための「軽量 DSL」
      に一歩近づく

Excel Advent Calendar 2025 では、他の参加者の方が
FILTER / LET / LAMBDA / Python 連携 など、
もっと別の切り口から Excel の可能性を掘ってくださるはずです。

本記事が、「研究室や授業での Excel の使い方を、もう一段階だけ踏み込んでみる」きっかけになれば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?