Swiftの行列計算など
使用頻度の高い計算を簡単にできるようにしました。
行列式の算出のためにLU分解についても書きましたが、ピボットの実装をしていません。
行列の対角要素に0が含まれている場合に不安定になります。
いつかはピボットを実装して、より汎用的に使えるようにしたいと思います。
import Foundation class Calc { //ベクトルの総和 func vsum(vector: [Double]) -> Double { var v_sum: Double = 0 for i in 0..<vector.count{ v_sum = v_sum + vector[i] } return v_sum } //平均 func vmean(vector:[Double]) -> Double { let mean = self.vsum(vector: vector)/Double(vector.count) return mean } //標準偏差 func std(vector:[Double]) -> Double { var std_temp = [Double](repeating:0, count: vector.count) for i in 0..<vector.count{ std_temp[i] = pow(vector[i]-self.vmean(vector: vector), 2) } let std: Double = sqrt(self.vmean(vector: std_temp)) return std } //zsocre正規化 func zscore(vector: [Double]) -> [Double] { var z = [Double](repeating:0, count: vector.count) for i in 0..<vector.count{ z[i] = (vector[i]-self.vmean(vector: vector))/self.std(vector: vector) } return z } //行列の転置 func transpose(matrix: [[Double]]) -> [[Double]]{ var matrix_T = [[Double]](repeating: [Double](repeating: 0, count: matrix.count), count: matrix[0].count) for i in 0..<matrix[0].count{ for j in 0..<matrix.count{ matrix_T[i][j] = matrix[j][i] } } return matrix_T } //ベクトルの内積 func vdot(vector: [Double], _vector:[Double]) -> Double { var vv: Double = 0 for i in 0..<vector.count{ let vv_temp: Double = vector[i] * _vector[i] vv += vv_temp } return vv } //スカラー掛けるベクトル func sxv(scalar: Double, vector: [Double]) -> [Double] { var sv = [Double](repeating:0, count: vector.count) for i in 0..<vector.count{ sv[i] = scalar * vector[i] } return sv } //スカラー足すベクトル func spv(scalar: Double, vector: [Double]) -> [Double] { var sv = [Double](repeating:0, count: vector.count) for i in 0..<vector.count{ sv[i] = scalar + vector[i] } return sv } //ベクトル足すベクトル func vpv(vector: [Double], vector_: [Double]) -> [Double] { var vv = [Double](repeating:0, count: vector.count) for i in 0..<vector.count{ vv[i] = vector[i] + vector_[i] } return vv } //ベクトル引くベクトル func vmv(vector: [Double], vector_: [Double]) -> [Double] { var vv = [Double](repeating:0, count: vector.count) for i in 0..<vector.count{ vv[i] = vector[i] - vector_[i] } return vv } //ベクトルの平方根 func vsqrt(vector: [Double]) -> [Double] { var sv = [Double](repeating:0, count: vector.count) for i in 0..<vector.count{ sv[i] = sqrt(vector[i]) } return sv } //ベクトルの累乗 func vpow(vector: [Double], power: Double) -> [Double] { var pv = [Double](repeating:0, count: vector.count) for i in 0..<vector.count{ pv[i] = pow(vector[i], power) } return pv } //ベクトルの指数 func vexp(vector: [Double]) -> [Double] { var ev = [Double](repeating:0, count: vector.count) for i in 0..<vector.count{ ev[i] = exp(vector[i]) } return ev } //スカラー掛ける行列 func sxm(scalar: Double, matrix: [[Double]]) -> [[Double]] { var sm = [[Double]](repeating: [Double](repeating: 0, count: matrix[0].count), count: matrix.count) for i in 0..<matrix.count{ for j in 0..<matrix[0].count{ sm[i][j] = scalar * matrix[i][j] } } return sm } //スカラー足す行列 func spm(scalar: Double, matrix: [[Double]]) -> [[Double]] { var sm = [[Double]](repeating: [Double](repeating: 0, count: matrix[0].count), count: matrix.count) for i in 0..<matrix.count{ for j in 0..<matrix[0].count{ sm[i][j] = scalar + matrix[i][j] } } return sm } //行列引く行列 func mmm(matrix: [[Double]], matrix_: [[Double]]) -> [[Double]] { var mm = [[Double]](repeating: [Double](repeating: 0, count: matrix[0].count), count: matrix.count) for i in 0..<matrix.count{ for j in 0..<matrix[0].count{ mm[i][j] = matrix[i][j] - matrix_[i][j] } } return mm } //行列足す行列 func mpm(matrix: [[Double]], matrix_: [[Double]]) -> [[Double]] { var mm = [[Double]](repeating: [Double](repeating: 0, count: matrix[0].count), count: matrix.count) for i in 0..<matrix.count{ for j in 0..<matrix[0].count{ mm[i][j] = matrix[i][j] + matrix_[i][j] } } return mm } //行列の内積 func mdot(matrix: [[Double]], _matrix: [[Double]]) -> [[Double]] { var mm = [[Double]](repeating: [Double](repeating: 0, count: _matrix[0].count), count: matrix.count) let _matrix_T = self.transpose(matrix: _matrix) for i in 0..<matrix.count{ for j in 0..<_matrix[0].count{ mm[j][i] = self.vdot(vector: matrix[j], _vector: _matrix_T[i]) } } return mm } //単位行列 func eye(n: Int) -> [[Double]] { var eye = [[Double]](repeating: [Double](repeating: 0, count: n), count: n) for i in 0..<eye.count{ for j in 0..<eye.count{ if i == j { eye[i][j] = 1 } } } return eye } //トレース func trace(matrix: [[Double]]) -> Double { var tr: Double = 0 for i in 0..<matrix.count { tr += matrix[i][i] } return tr } //LU分解 func LU(matrix: [[Double]]) -> (L: [[Double]], U: [[Double]]) { //ピボット選択は行わない //係数行列の対角要素のいずれかが0(または非常に小さいor他の要素に比べ非常に小さい)のとき不安定 //下三角行列Lの対角要素は1 var A: [[Double]] = matrix for i in 0..<A.count { for j in i+1..<A.count { A[j][i] = A[j][i] / A[i][i] for k in i+1..<A.count { A[j][k] = A[j][k] - A[j][i] * A[i][k] } } } var L = self.eye(n: A.count) var U = [[Double]](repeating: [Double](repeating: 0, count: A[0].count), count: A.count) for i in 0..<A.count { for j in 0..<A.count { if i>j { L[i][j] = A[i][j] } else { U[i][j] = A[i][j] } } } return (L, U) } //行列式 func det(matrix: [[Double]]) -> Double { //LU分解を使うため、対角要素が全て0以上であることを仮定 let U = self.LU(matrix: matrix).U var det: Double = 1 for i in 0..<U.count{ det *= U[i][i] } return det } //逆行列 func inv(matrix: [[Double]]) -> [[Double]] { //掃き出し法 var m: [[Double]] = matrix var m_inv = self.eye(n: m.count) for i in 0..<m.count{ var temp: Double = 1/m[i][i] for j in 0..<m.count{ m[i][j] *= temp m_inv[i][j] *= temp } for j in 0..<m.count{ if i != j{ temp = m[j][i] for k in 0..<m.count{ m[j][k] -= m[i][k] * temp m_inv[j][k] -= m_inv[i][k]*temp } } } } return m_inv } //擬似弱行列 func pinv(matrix: [[Double]]) -> [[Double]] { let m_pinv: [[Double]] = self.mdot(matrix: self.inv(matrix: self.mdot(matrix: self.transpose(matrix: matrix), _matrix: matrix)), _matrix: self.transpose(matrix: matrix)) return m_pinv } } let calc = Calc() let x: [Double] = [170, 16, 175, 15] let y_mean = calc.vmean(vector: x) let y_std = calc.std(vector: x) let y_norm = calc.zscore(vector: x) print("平均:", y_mean) print("標準偏差:", y_std) print("zscore正規化:", y_norm) let a: [[Double]] = [[1,2],[3,4],[5,6]] let b: [[Double]] = [[7,8,9],[10,11,12]] let c = calc.mdot(matrix:a, _matrix:b) print("行列の内積:",c) let d: [Double] = [1,2,3] let e: [Double] = [4,5,6] let f = calc.vdot(vector:d, _vector:e) print("ベクトルの内積:",f) let g = calc.sxv(scalar: 2, vector: d) print("スカラー掛けるベクトル:",g) let h = calc.sxm(scalar: 2, matrix: a) print("スカラー掛ける行列:",h) let l: [[Double]] = [[1,2,0,-1],[-1,1,2,0],[2,0,1,1],[1,-2,-1,1]] let m = calc.det(matrix: l) print("行列式:",m) let o = calc.inv(matrix: l) print("逆行列:",o) let p = calc.pinv(matrix: l) print("擬似逆行列:",p)