Breeze

Scala用の数値計算ライブラリ。線形代数、統計、機械学習のための包括的な数値処理機能を提供。NumPyライクなAPIで行列演算、信号処理、最適化アルゴリズムをサポート。

Scala数値計算線形代数機械学習NumPy行列演算最適化統計

フレームワーク

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教育カリキュラムでも標準的に採用されています。