Breeze
Scala用の数値計算ライブラリ。線形代数、統計、機械学習のための包括的な数値処理機能を提供。NumPyライクなAPIで行列演算、信号処理、最適化アルゴリズムをサポート。
フレームワーク
Breeze
概要
BreezeはScala用の数値計算ライブラリです。線形代数、統計、機械学習のための包括的な数値処理機能を提供し、NumPyライクなAPIで行列演算、信号処理、最適化アルゴリズムをサポートします。
詳細
Breeze(ブリーズ)は、2011年に開発が開始されたScala向けの数値計算ライブラリです。ScalaNLPプロジェクトの一部として開発され、PythonのNumPyやMATLABに匹敵する数値計算機能をScalaで提供することを目的としています。最大の特徴は、Scalaの型安全性を保ちながら、直感的で表現力豊かな数値計算APIを提供することです。DenseVectorとDenseMatrixを中心とした線形代数演算、統計関数、最適化アルゴリズム、信号処理機能を統合。BLAS(Basic Linear Algebra Subprograms)との統合により、高速な行列演算を実現しています。Spark MLlibとの統合も提供されており、分散機械学習環境での利用が可能。関数型プログラミングの原則に従い、イミュータブルなデータ構造と純粋関数によるAPIを基本としながら、パフォーマンスが必要な場面ではミュータブルな操作もサポートしています。
メリット・デメリット
メリット
- NumPyライクなAPI: 直感的で学習しやすいインターフェース
- 型安全性: Scalaの型システムによる実行時エラーの削減
- 高速演算: BLAS統合による最適化された行列演算
- 豊富な機能: 線形代数、統計、最適化の包括的サポート
- Spark統合: 分散機械学習での利用が可能
- 関数型サポート: 純粋関数による予測可能な動作
デメリット
- メモリ使用量: 大規模行列での高いメモリ消費
- 学習コスト: Scalaと数値計算の両方の知識が必要
- パフォーマンス: NumPyと比べると一部の操作で劣る場合
- エコシステム: Pythonの科学計算環境と比べて限定的
主な使用事例
- 科学計算とシミュレーション
- 機械学習アルゴリズムの実装
- 信号処理と画像処理
- 統計分析とデータ解析
- 最適化問題の解決
- 数値解析
- 研究・教育用途
基本的な使い方
依存関係の追加
libraryDependencies ++= Seq(
"org.scalanlp" %% "breeze" % "2.1.0",
"org.scalanlp" %% "breeze-natives" % "2.1.0" // BLAS最適化
)
基本的なベクトル操作
import breeze.linalg._
import breeze.numerics._
// ベクトルの作成
val v1 = DenseVector(1.0, 2.0, 3.0, 4.0)
val v2 = DenseVector(2.0, 3.0, 4.0, 5.0)
// 基本的な演算
val sum = v1 + v2
val product = v1 * v2 // 要素ごとの積
val dotProduct = v1 dot v2 // 内積
val norm = norm(v1) // ノルム
println(s"Sum: $sum")
println(s"Element-wise product: $product")
println(s"Dot product: $dotProduct")
println(s"Norm: $norm")
// ベクトルの変換
val doubled = v1.map(_ * 2)
val filtered = v1.filter(_ > 2.0)
val normalized = v1 / norm(v1)
println(s"Doubled: $doubled")
println(s"Filtered: $filtered")
println(s"Normalized: $normalized")
行列操作
import breeze.linalg._
import breeze.numerics._
// 行列の作成
val matrix1 = DenseMatrix(
(1.0, 2.0, 3.0),
(4.0, 5.0, 6.0),
(7.0, 8.0, 9.0)
)
val matrix2 = DenseMatrix(
(2.0, 0.0, 1.0),
(1.0, 3.0, 2.0),
(0.0, 1.0, 4.0)
)
// 行列演算
val matrixSum = matrix1 + matrix2
val matrixProduct = matrix1 * matrix2
val transpose = matrix1.t
val inverse = inv(matrix2)
println(s"Matrix sum:\n$matrixSum")
println(s"Matrix product:\n$matrixProduct")
println(s"Transpose:\n$transpose")
println(s"Inverse:\n$inverse")
// 行列の分解
val svd.SVD(u, s, vt) = svd(matrix1)
println(s"SVD - U:\n$u")
println(s"SVD - S: $s")
println(s"SVD - Vt:\n$vt")
統計関数
import breeze.linalg._
import breeze.stats._
// データの準備
val data = DenseVector(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)
// 基本統計量
val mean = breeze.stats.mean(data)
val variance = breeze.stats.variance(data)
val stddev = breeze.stats.stddev(data)
val median = breeze.stats.median(data)
println(s"Mean: $mean")
println(s"Variance: $variance")
println(s"Standard deviation: $stddev")
println(s"Median: $median")
// 分布
import breeze.stats.distributions._
val normal = Gaussian(0.0, 1.0)
val samples = normal.sample(1000)
val density = normal.pdf(0.0)
println(s"Normal distribution density at 0: $density")
println(s"Sample size: ${samples.length}")
// ヒストグラム
val hist = breeze.stats.hist(DenseVector(samples: _*), 20)
println(s"Histogram bins: ${hist.hist.length}")
最適化
import breeze.optimize._
import breeze.linalg._
// 目的関数の定義(Rosenbrock関数)
def rosenbrock(x: DenseVector[Double]): Double = {
val a = 1.0
val b = 100.0
(a - x(0)) * (a - x(0)) + b * (x(1) - x(0) * x(0)) * (x(1) - x(0) * x(0))
}
// 勾配の定義
def rosenbrockGradient(x: DenseVector[Double]): DenseVector[Double] = {
val a = 1.0
val b = 100.0
DenseVector(
-2.0 * (a - x(0)) - 4.0 * b * x(0) * (x(1) - x(0) * x(0)),
2.0 * b * (x(1) - x(0) * x(0))
)
}
// 最適化問題の設定
val f = new DiffFunction[DenseVector[Double]] {
def calculate(x: DenseVector[Double]) = (rosenbrock(x), rosenbrockGradient(x))
}
// 初期値
val initialGuess = DenseVector(-1.0, 1.0)
// LBFGS法での最適化
val lbfgs = new LBFGS[DenseVector[Double]]()
val result = lbfgs.minimize(f, initialGuess)
println(s"Optimization result: $result")
println(s"Minimum value: ${rosenbrock(result)}")
機械学習の例
import breeze.linalg._
import breeze.numerics._
import breeze.stats._
// 線形回帰の実装
object LinearRegression {
def fit(X: DenseMatrix[Double], y: DenseVector[Double]): DenseVector[Double] = {
// 正規方程式を使用: β = (X^T X)^(-1) X^T y
val Xt = X.t
val XtX = Xt * X
val XtXinv = inv(XtX)
val Xty = Xt * y
XtXinv * Xty
}
def predict(X: DenseMatrix[Double], weights: DenseVector[Double]): DenseVector[Double] = {
X * weights
}
}
// サンプルデータの生成
val n = 100
val X = DenseMatrix.rand(n, 3)
val trueWeights = DenseVector(2.0, -1.0, 0.5)
val noise = DenseVector.rand(n) * 0.1
val y = X * trueWeights + noise
// 線形回帰の実行
val estimatedWeights = LinearRegression.fit(X, y)
val predictions = LinearRegression.predict(X, estimatedWeights)
// 評価
val mse = mean((y - predictions) :* (y - predictions))
println(s"True weights: $trueWeights")
println(s"Estimated weights: $estimatedWeights")
println(s"Mean Squared Error: $mse")
信号処理
import breeze.linalg._
import breeze.numerics._
import breeze.signal._
// 信号の生成
val t = linspace(0.0, 1.0, 1000)
val frequency1 = 50.0
val frequency2 = 120.0
val signal = sin(2.0 * math.Pi * frequency1 * t) + 0.5 * sin(2.0 * math.Pi * frequency2 * t)
// ノイズの追加
val noise = DenseVector.rand(signal.length) * 0.2 - 0.1
val noisySignal = signal + noise
// フィルタリング
val windowSize = 10
val filtered = DenseVector.zeros[Double](signal.length)
for (i <- windowSize until signal.length - windowSize) {
filtered(i) = mean(noisySignal(i - windowSize to i + windowSize))
}
// FFT
val fft = fourierTr(noisySignal)
val magnitude = fft.map(c => math.sqrt(c.real * c.real + c.imag * c.imag))
println(s"Original signal length: ${signal.length}")
println(s"Filtered signal length: ${filtered.length}")
println(s"FFT magnitude length: ${magnitude.length}")
画像処理の例
import breeze.linalg._
import breeze.numerics._
// 画像データの表現(グレースケール)
val width = 100
val height = 100
val image = DenseMatrix.rand(height, width)
// ガウシアンフィルタの作成
def gaussianKernel(size: Int, sigma: Double): DenseMatrix[Double] = {
val kernel = DenseMatrix.zeros[Double](size, size)
val center = size / 2
var sum = 0.0
for (i <- 0 until size; j <- 0 until size) {
val x = i - center
val y = j - center
val value = math.exp(-(x * x + y * y) / (2 * sigma * sigma))
kernel(i, j) = value
sum += value
}
kernel / sum // 正規化
}
// 畳み込み演算
def convolve(image: DenseMatrix[Double], kernel: DenseMatrix[Double]): DenseMatrix[Double] = {
val result = DenseMatrix.zeros[Double](image.rows, image.cols)
val kSize = kernel.rows
val kCenter = kSize / 2
for (i <- kCenter until image.rows - kCenter;
j <- kCenter until image.cols - kCenter) {
var sum = 0.0
for (ki <- 0 until kSize; kj <- 0 until kSize) {
sum += image(i - kCenter + ki, j - kCenter + kj) * kernel(ki, kj)
}
result(i, j) = sum
}
result
}
// フィルタの適用
val gaussianFilter = gaussianKernel(5, 1.0)
val filteredImage = convolve(image, gaussianFilter)
println(s"Original image size: ${image.rows} x ${image.cols}")
println(s"Filtered image size: ${filteredImage.rows} x ${filteredImage.cols}")
最新のトレンド(2025年)
- Scala 3対応: 最新のScala機能との統合
- GPU加速: CUDA対応による高速化
- Spark 3.5統合: 分散機械学習の強化
- 深層学習支援: TensorFlow Scalaとの連携
- WebAssembly: ブラウザでの数値計算
まとめ
Breezeは2025年において、Scala科学計算エコシステムの基盤として継続的に利用されています。型安全性、NumPyライクなAPI、高速演算により、Scalaでの数値計算・機械学習開発を支援。Spark MLlibとの組み合わせで分散機械学習処理に活用され、大学・研究機関でのScala教育カリキュラムでも標準的に採用されています。