機械学習から始める Clojure 入門¶
Clojure は JVM 上で動く LISP で、不変のデータ(マップ・ベクタ)と、それを変換する関数を中心に組み立てる言語です。型を宣言しないという点では Python・Ruby と同じ動的型付けですが、データの表し方と書き方の単位は S 式と関数の合成になります。本シリーズでは、Python 版と同じ題材の機械学習のアルゴリズムを TDD で自作し、JVM の機械学習ライブラリ Tribuo と突き合わせながら、Clojure の書き方とエコシステムを学びます。
Clojure 版は 3 つの軸で対比します。1 つは Scala 版・Java 版 で、同じ JVM・同じ Tribuo・同じ JDK 21 を使います。乱数の並びまで一致するので、数値が合うかどうかを言語をまたいで確かめられます。2 つめは F# 版 で、不変のデータと関数でデータを変換する流儀が近いところです。3 つめは Ruby 版・Python 版 で、型を宣言しない言語として、テストが唯一の安全網になる点が同じです。
特徴¶
- 表を素のマップとベクタで表す: データフレームのライブラリを使わず、列名をキーワードにしたマップの並び(
{:身長 170 :体重 60 :年代 20 :派閥 "きのこ"}のベクタ)でデータを持つ。キーワードはそれ自身が関数なので、(:身長 person)で値を引ける - 型を宣言しない: 引数にも戻り値にも型を書かない。型の誤りや綴りの間違いは、実行して初めて分かる。ただし未定義の var はコンパイル時に落ちるので、Red の出方は Python 版・Ruby 版と少し違う
- 失敗は Java の例外で表す:
IllegalArgumentExceptionなど JDK の例外をそのまま投げる。Rust 版のResult・Go 版のerrorとは逆の流儀で、Java 版・Ruby 版に近い - Java の相互運用がそのまま使える:
(java.io.File. path)・(Long/parseLong cell)のように、JDK と Tribuo の API を包み直さずに呼べる - 名前空間とファイル名の対応: 名前空間のダッシュはファイル名のアンダースコアになる(
getting-started-ml.dataset→getting_started_ml/dataset.clj)
ほかの版との違い¶
- Notebook による探索と可視化の節は設けません。グラフは Python 版 と Kotlin 版 の可視化の節を参照してください
- 総合演習(付録 A)の解答例は作りません。演習問題は言語に依存しないので、Python 版の付録 A の問題に Clojure で取り組んでください
- 乱数は
java.util.Randomと Fisher-Yates を使うので、第 2 章以降の分割は Java 版・Scala 版と一致し、Python 版とは一致しません。記事の数値は Clojure 版の実装で実測した値を載せます - CSV は
clojure.data.csvを使いますが、BOM は取り除かれません。先頭の列名から自分で取り除きます。tech.ml.datasetなら取り除いてくれますが、データフレームのライブラリを使わないというシリーズの方針から採用しませんでした(ADR 011) clojure.testにはテストを飛ばす仕組みがありません。実データのテストは、Rust 版と同じく早期に戻って理由を標準エラーに出します(Ruby 版の Minitest のskipとの対比)deps.ednには lock ファイルに当たるものがありません。再現性は依存の版を固定して書くことに頼ります
開発環境¶
| ツール | 用途 |
|---|---|
Clojure 1.12・Clojure CLI(deps.edn) |
言語・依存管理・別名によるタスク |
| clojure.test・test-runner | テスティングフレームワーク(clojure -M:test) |
| cljfmt | 整形(cljfmt check で検査) |
| clj-kondo | 静的解析(clj-kondo --lint src test --fail-level warning) |
| cloverage | カバレッジ(clojure -M:coverage) |
Nix の環境(nix develop .#clojure)は Clojure CLI 1.12.3.1577・Leiningen 2.11.2・babashka 1.12.209・clojure-lsp 2025.11.28・clj-kondo 2025.10.23・cljfmt 0.15.6 です。java コマンドは 25.0.2 ですが、Clojure は JDK 21.0.8 で動きます(Java 版・Kotlin 版・Scala 版と同じ JDK)。clj-kondo と cljfmt はもともと環境に入っていなかったので、環境定義(ops/nix/environments/clojure/shell.nix)に足しました。その経緯は第 5〜6 章で扱います。
ライブラリ¶
| ライブラリ | 用途 | 初出 |
|---|---|---|
| clojure.data.csv | CSV の読み込み(BOM は自分で取り除く) | 第 1 章 |
java.util.Random |
乱数(訓練データとテストデータの分割) | 第 2 章 |
| Tribuo | 決定木・ランダムフォレスト・回帰・ロジスティック回帰・K-means・評価指標 | 第 3 章 |
java.io.InputStreamReader |
Shift_JIS の CSV | 第 9 章 |
EDN(pr-str・read-string) |
学習済みモデルの保存 | 第 8 章 |
| Ring・Jetty・Cheshire | 予測 API | 第 15 章 |
選定の理由と、章ごとにライブラリへ置き換えられる範囲は ADR 011 を参照してください。
サンプルコード¶
サンプルコードは apps/clojure/ にあります。学習データの配置方法は 第 1 章 の「題材とデータ」を参照してください。
nix develop .#clojure
cd apps/clojure
clojure -M:test
clojure -M:run chapter01
リポジトリのルートで npx gulp apps:check:clojure を実行すると、CI と同じ順(整形・静的解析・テスト・カバレッジ)でまとめて検査できます。
章構成¶
全 15 章を公開しています。
第 1 部: 機械学習と TDD の基本サイクル¶
| 章 | テーマ | 状態 |
|---|---|---|
| 第 1 章 | 機械学習とはじめてのテスト | 公開済み |
| 第 2 章 | データの前処理と三角測量 | 公開済み |
| 第 3 章 | 決定木による分類と明白な実装 | 公開済み |
第 2 部: 開発環境と自動化¶
| 章 | テーマ | 状態 |
|---|---|---|
| 第 4 章 | バージョン管理とデータ管理 | 公開済み |
| 第 5 章 | パッケージ管理と静的解析 | 公開済み |
| 第 6 章 | タスクランナーと CI/CD | 公開済み |
第 3 部: 回帰と実践的な前処理¶
| 章 | テーマ | 状態 |
|---|---|---|
| 第 7 章 | 線形回帰による数値予測 | 公開済み |
| 第 8 章 | 実践的な分類と前処理パイプライン | 公開済み |
| 第 9 章 | 特徴量エンジニアリング | 公開済み |
第 4 部: モデルの改善と評価¶
| 章 | テーマ | 状態 |
|---|---|---|
| 第 10 章 | ロジスティック回帰とアンサンブル学習 | 公開済み |
| 第 11 章 | 評価指標と交差検証 | 公開済み |
| 第 12 章 | 正則化とモデル選択 | 公開済み |
第 5 部: 教師なし学習と実運用¶
| 章 | テーマ | 状態 |
|---|---|---|
| 第 13 章 | 主成分分析による次元削減 | 公開済み |
| 第 14 章 | K-means によるクラスタリング | 公開済み |
| 第 15 章 | 機械学習 API とモジュール設計 | 公開済み |
付録¶
総合演習(Bank)の解答例は Python 版のみです。演習問題は言語に依存しないので、Python 版の付録 A の問題に Clojure で取り組んでください。