コンテンツにスキップ

第01回 再現可能な分析パイプライン

科目:ビッグデータ応用Ⅱ〔特徴量エンジニアリング〕
担当:小野原彩香
対象:3年生(後期)


この授業の進め方

この授業は個人作業・自己ペース型です。以下を前提として設計しています。

  • ハンズオン手順は授業時間内に全部終わらせる必要はありません。続きは持ち帰って自分のペースで進めてください。
  • 演習課題の締め切りは2週間後です。早く終わった場合は早めに出しても、ギリギリまでかかっても、どちらでも構いません。
  • グループワークや口頭発表はありません。全作業は個人で行います。
  • 授業中に質問しにくい場合は、メールで質問を送ってください(返信は数日以内)。
  • この資料は手元に保存して、授業外でも参照できます。コマンドやコードはコピーして使ってください。
  • 躓いたときのために、各手順の後に「うまくいかないとき」の対処法を記載しています。

学習目標

  1. 再現性がなぜデータ分析において重要かを説明できる
  2. Makefileを使って分析パイプラインを自動化・文書化できる
  3. READMEに必要な情報を整理し、他者が再現できる文書を書ける
  4. 再現性の3原則(環境の固定・手順の明示・乱数シードの固定)を実践できる

1. なぜ再現性が重要か

1.1 再現性のない分析が引き起こす問題

データ分析プロジェクトでは、以下のような状況が頻繁に起こります。

  • 「半年前に作ったグラフ、もう一度作って」と言われたが、手順を忘れた
  • 別のPC・別のメンバーが同じコードを実行しても、結果が微妙に異なる
  • どのファイルが最新バージョンかわからない(分析_最終版_最終版2_確定.xlsx 問題)
  • パッケージのバージョンを変えたら、モデルの精度が突然変わった

これらはすべて再現性の欠如が原因です。学術論文・企業レポート・行政データ活用のいずれにおいても、再現できない分析は信頼されません。

再現可能な分析を作ることは、未来の自分へのやさしさでもあります。数ヶ月後の自分が同じ作業を最初からやり直さなくて済むように、手順をコードで残す習慣を身につけましょう。

1.2 再現性の3原則

原則 内容 実践方法
環境の固定 使用するソフトウェアのバージョンを明示・固定する requirements.txt, conda env export, Dockerfile
手順の明示 データ取得から結果出力まで、すべての手順をコードで記述する Makefile, シェルスクリプト
乱数シードの固定 ランダム性を持つ処理の結果を固定する random.seed(42), np.random.seed(42)

1.3 本講義の素材

本講義では、学内配布の「地理空間情報LLM」ログデータを使います。このデータには:

  • ユーザーの問い合わせ地点(緯度・経度)
  • 問い合わせ時刻
  • 返答カテゴリ

などが含まれています。毎回の授業で、このデータに対して異なる処理を加え、最終的に機械学習用の特徴量を構築することが本講義の目標です。


2. Makefileの基礎

2.1 Makefileとは

Makefile は、もともとC言語のビルドツールとして開発された仕組みですが、データ分析のパイプライン管理にも広く使われています。コマンドの依存関係を定義し、「何が変わったら何を実行しなおすか」を管理できます。

まずは「便利なコマンドをまとめたメモ帳」だと思ってください。make setup と打てば環境が整い、make all と打てば分析が最初から最後まで走る、というものです。

2.2 Makefileの基本構文

ターゲット名: 依存ファイル1 依存ファイル2
    実行するコマンド(先頭はタブ文字)

重要: コマンドの先頭は必ずタブ文字(スペースではなく)を使います。これはMakefileの唯一の「落とし穴」です。エディタがスペースに自動変換する場合があるので注意してください。

うまくいかないとき(タブ関連): Makefile:XX: *** missing separator. Stop. というエラーが出たら、コマンド行の先頭がスペースになっています。その行をいったん削除して、タブキーで再入力してください。

2.3 データ分析用Makefileのサンプル

以下は、地理空間情報LLMログデータの分析パイプラインの例です。このサンプルをそのままコピーして使ってください。

# ========================================
# Makefile: 地理空間情報LLMログ分析パイプライン
# 担当: 小野原彩香(ビッグデータ応用Ⅱ)
# ========================================

# 変数の定義
PYTHON    := python3
DATA_DIR  := data
RAW_DIR   := $(DATA_DIR)/raw
PROC_DIR  := $(DATA_DIR)/processed
RESULT_DIR := results

# デフォルトターゲット(makeだけ実行したときに動く)
.DEFAULT_GOAL := all

# .PHONYはファイルを生成しないターゲットを宣言する
.PHONY: all setup download process analyze clean help

# すべての処理を順番に実行
all: setup download process analyze
    @echo "パイプラインが完了しました"

# 環境セットアップ:Pythonパッケージのインストール
setup:
    @echo "==> 環境をセットアップします..."
    $(PYTHON) -m pip install --upgrade pip
    $(PYTHON) -m pip install -r requirements.txt
    mkdir -p $(RAW_DIR) $(PROC_DIR) $(RESULT_DIR)
    @echo "セットアップ完了"

# データダウンロード:学内サーバーからログデータを取得
download: $(RAW_DIR)/llm_log.geojson

$(RAW_DIR)/llm_log.geojson:
    @echo "==> データをダウンロードします..."
    curl -o $@ https://campus-data.example.ac.jp/llm_log.geojson
    @echo "ダウンロード完了: $@"

# データ前処理:座標変換・クリーニング
process: $(PROC_DIR)/llm_log_clean.csv

$(PROC_DIR)/llm_log_clean.csv: $(RAW_DIR)/llm_log.geojson
    @echo "==> データを前処理します..."
    $(PYTHON) src/preprocess.py \
        --input $< \
        --output $@ \
        --seed 42
    @echo "前処理完了: $@"

# 分析実行:特徴量エンジニアリングと集計
analyze: $(RESULT_DIR)/summary.csv $(RESULT_DIR)/feature_matrix.csv

$(RESULT_DIR)/summary.csv $(RESULT_DIR)/feature_matrix.csv: $(PROC_DIR)/llm_log_clean.csv
    @echo "==> 分析を実行します..."
    $(PYTHON) src/analyze.py \
        --input $< \
        --outdir $(RESULT_DIR) \
        --seed 42
    @echo "分析完了"

# クリーンアップ:生成ファイルをすべて削除
clean:
    @echo "==> 生成ファイルを削除します..."
    rm -rf $(PROC_DIR)/* $(RESULT_DIR)/*
    @echo "クリーンアップ完了"

# ダウンロードしたデータも含めて削除
clean-all: clean
    rm -rf $(RAW_DIR)/*
    @echo "ダウンロードデータも削除しました"

# ヘルプ表示
help:
    @echo "利用可能なコマンド:"
    @echo "  make setup     - 環境セットアップ(パッケージインストール)"
    @echo "  make download  - データのダウンロード"
    @echo "  make process   - データの前処理"
    @echo "  make analyze   - 分析の実行"
    @echo "  make all       - 上記すべてを順番に実行"
    @echo "  make clean     - 処理済みファイル・結果を削除"
    @echo "  make clean-all - ダウンロードデータも含め全削除"

2.4 makeコマンドの基本的な使い方

# ヘルプを表示する(まず何があるか確認する)
make help

# 環境のセットアップだけ実行する
make setup

# データのダウンロードだけ実行する
make download

# すべての処理を順番に実行する
make all

# または単に make(.DEFAULT_GOALがallなので同じ)
make

# 処理済みファイルを削除して、やり直す
make clean
make all

うまくいかないとき(make が見つからない): make: command not found と表示された場合、macOSでは xcode-select --install を実行してください。Windowsでは WSL(Windows Subsystem for Linux)か Git Bash を使うと make が使えます。

2.5 Makefileの便利な機能:差分実行

Makefileは、ファイルのタイムスタンプを見て、変更がなければ処理をスキップします。途中まで終わっていたら、終わったところから再開できます。

# 1回目: download → process → analyze がすべて実行される
make all

# 2回目: すべてのファイルが最新なので何もしない
make all
# 出力: make: Nothing to be done for 'all'.

# raw データを変更した場合: process と analyze だけ再実行される
touch data/raw/llm_log.geojson
make all

3. READMEの書き方

3.1 なぜREADMEが重要か

コードと同じくらい重要なのが文書(ドキュメント)です。3ヶ月後の自分でも、初めてそのプロジェクトに触れる人でも、READMEを読めば:

  • 何をするプロジェクトか
  • どうやって実行するか
  • 何が必要か

がすぐにわかることが理想です。

READMEは「自分が忘れたときのメモ」として書くと書きやすいです。完璧な文書を目指す必要はなく、自分が後で読んで理解できればOKです。

3.2 READMEのテンプレート

以下のテンプレートを README.md として保存してください。(ここを書く) と書いてある部分だけ自分の内容に書き換えれば完成です。

# プロジェクト名(ここを書く)

(ここを書く:一文でプロジェクトの目的を書く)

例: 学内配布「地理空間情報LLM」のログデータから空間特徴量を抽出し、
   利用行動の地域パターンを分析するパイプライン。

## 環境要件

- OS: (ここを書く:例 macOS 14)
- Python: (ここを書く:例 3.11.4)
- GDAL: 3.6 以上(`ogr2ogr`, `gdalinfo` を使用)
- make: GNU Make 4.0 以上

### Pythonパッケージ

requirements.txt を参照。

## セットアップと使い方

### 1. 環境のセットアップ

make setup

### 2. データの取得と分析の実行

make all

### 3. 個別に実行する場合

make download   # データのダウンロードのみ
make process    # 前処理のみ
make analyze    # 分析のみ

### 4. リセット

make clean      # 処理済みファイルを削除
make clean-all  # ダウンロードデータも含め全削除

## ディレクトリ構成

プロジェクトルート/
├── Makefile              # パイプライン定義
├── README.md             # このファイル
├── requirements.txt      # Pythonパッケージ一覧
├── data/
│   ├── raw/              # 生データ(変更しない)
│   │   └── llm_log.geojson
│   └── processed/        # 前処理済みデータ
│       └── llm_log_clean.csv
├── src/
│   ├── preprocess.py     # 前処理スクリプト
│   └── analyze.py        # 分析スクリプト
└── results/              # 分析結果
    ├── summary.csv
    └── feature_matrix.csv

## 再現性について

- Pythonパッケージのバージョンは requirements.txt で固定
- 乱数シードはすべてのスクリプトで seed=42 を使用
- データは学内限定配布。外部への公開・転送は禁止

3.3 requirements.txtの書き方

# requirements.txt
# 生成方法: pip freeze > requirements.txt
# または手動で主要パッケージのみ記述(バージョンを固定する)

geopandas==0.14.1
pandas==2.1.4
numpy==1.26.2
matplotlib==3.8.2
scikit-learn==1.3.2
pyproj==3.6.1
shapely==2.0.2
fiona==1.9.5

4. ハンズオン手順

所要時間の目安: 全手順で60〜90分程度です。授業時間内に終わらなければ持ち帰ってください。どこまで終わったかをメモしておくと、再開しやすいです。

各手順は独立しているので、「手順1だけやって今日は終わり」でも問題ありません。

手順1: プロジェクトディレクトリを作成する

# 作業ディレクトリを作成
mkdir -p ~/bigdata2/pipeline_practice
cd ~/bigdata2/pipeline_practice

# 必要なサブディレクトリを作成
mkdir -p data/raw data/processed results src notebooks

作成できたか確認する:

ls -la
# data/  notebooks/  results/  src/ が表示されればOK

うまくいかないとき: cd のあとにディレクトリが見つからないエラーが出たら、mkdir -p が先に実行されているか確認してください。コマンドは1行ずつ実行するのが確実です。

手順2: requirements.txtを作成する

テキストエディタ(VSCodeなど)で requirements.txt を作り、以下を貼り付けて保存してください。

geopandas==0.14.1
pandas==2.1.4
numpy==1.26.2
matplotlib==3.8.2
scikit-learn==1.3.2
pyproj==3.6.1
shapely==2.0.2

または、ターミナルで以下を実行しても作成できます(コピーして貼り付けてください):

cat > requirements.txt << 'EOF'
geopandas==0.14.1
pandas==2.1.4
numpy==1.26.2
matplotlib==3.8.2
scikit-learn==1.3.2
pyproj==3.6.1
shapely==2.0.2
EOF

手順3: Makefileを作成する

2.3節のMakefileをコピーして、Makefile(拡張子なし)として保存してください。ファイル名は必ず Makefile です(Makefile.txt にしないよう注意)。

うまくいかないとき(Makefileが動かない): ファイル名に拡張子が付いていないか確認してください。ls -la を実行して Makefile と表示されればOKです。

手順4: 乱数シード固定のサンプルスクリプトを作成する

src/preprocess.py を作成し、以下を貼り付けて保存してください。

# src/preprocess.py
import random
import numpy as np
import pandas as pd
import geopandas as gpd
import argparse

def set_seed(seed: int = 42):
    """再現性のために乱数シードを固定する"""
    random.seed(seed)
    np.random.seed(seed)

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--input", required=True)
    parser.add_argument("--output", required=True)
    parser.add_argument("--seed", type=int, default=42)
    args = parser.parse_args()

    # 乱数シードを固定
    set_seed(args.seed)
    print(f"乱数シード: {args.seed}")

    # GeoJSONを読み込む
    gdf = gpd.read_file(args.input)
    print(f"読み込み件数: {len(gdf)}")

    # 前処理(欠損値の除去)
    gdf_clean = gdf.dropna(subset=["geometry"])
    print(f"前処理後: {len(gdf_clean)}")

    # 結果を保存
    gdf_clean.to_csv(args.output, index=False)
    print(f"保存完了: {args.output}")

if __name__ == "__main__":
    main()

手順5: makeを実行して動作を確認する

# ヘルプを表示(動作確認)
make help

# セットアップを実行(パッケージのインストール)
make setup

インストールが完了したら、環境のスナップショットを保存します:

pip freeze > env_snapshot.txt

うまくいかないとき(パッケージのインストールエラー): pip install geopandas が失敗する場合、conda install -c conda-forge geopandas を試してください。GDALやFIONAの依存関係でエラーになることがあります。

手順6: Makefileの差分実行を体験する(余裕があれば)

# 最初の実行(すべて実行される)
make process

# 2回目の実行(変更なし→スキップ)
make process

# 入力ファイルのタイムスタンプを更新して再実行を促す
touch data/raw/llm_log.geojson
make process   # 今度は再実行される

5. 演習課題

締め切り:2週間後(次の次の授業の前日23:59)

提出方法:作成したファイルをzipにまとめてメールで送付(提出先アドレスは別途案内)

再提出:締め切り後も1週間以内であれば再提出可能です。


課題1(必須)

~/bigdata2/week01/ にプロジェクトを作成し、以下の4つのターゲットを持つMakefileを作成してください。

ターゲット 内容
setup 必要なディレクトリ(data/raw, data/processed, results)を作成する
download 授業で配布したサンプルデータを data/raw/ にコピーする
check データの行数と列数を表示する
clean data/processed/ と results/ の中身を削除する

make all で setup → download → check が順番に実行されることを確認してください。

チェックコマンドの例(参考):

# データの行数と列数を表示するコマンド(checkターゲットで使う)
python3 -c "
import pandas as pd
df = pd.read_csv('data/raw/sample.csv')
print(f'行数: {len(df)}, 列数: {len(df.columns)}')
print(f'列名: {list(df.columns)}')
"

課題2(必須)

作成したプロジェクトの README.md を3.2節のテンプレートを参考に作成し、以下の項目を埋めてください。

  • プロジェクトの目的(1〜2文)
  • 実行環境(OSとPythonバージョン)
  • ディレクトリ構成(実際に作成したもの)

課題3(任意・加点対象)

src/preprocess.py に、乱数シードを引数で変えても出力結果が変わらないことを確認する処理を追加し、make process で実行できるようにしてください。


まとめ

項目 キーワード
再現性の3原則 環境の固定・手順の明示・乱数シードの固定
手順の自動化ツール Makefile(ターゲット・依存関係・コマンド)
文書化ツール README.md(概要・環境要件・使い方・構成)
環境の固定 requirements.txt, pip freeze
乱数シードの固定 random.seed(42), np.random.seed(42)

次回(第02回)は、地理空間データの座標参照系(CRS)の変換を、GDAL/OGRのコマンドラインツールを使って実践します。今回の作業ディレクトリ(~/bigdata2/pipeline_practice)は次回以降も使います。


ビッグデータ応用Ⅱ〔特徴量エンジニアリング〕 / 担当:小野原彩香